 |
| tdbengine-news vom 19.11.2003 |  |
 |
 |
Seit der letzten News ist viel Zeit vergangen. Das liegt aber mitnichten daran, dass sich bei der tdbengine nichts mehr tut, genau das Gegenteil ist der Fall: Es gibt eine neue Version 6.2.9 mit einer ganzen Reihe neuer Features und Möglichkeiten, die weiter unten beschrieben werden.
CGI-Anwendungen ohne Apache-Konfiguration
Bereits in der der Version 6.2.8 (Linux und FreeBSD) war die Option eingebaut, mit direct_scripting direkt ausführbare CGI-Scripten erzeugen zu können. Leider sind die Möglichkeiten, die sich daraus ergeben, nicht klar genug herausgestellt worden: Jetzt kann die tdbengine bei allen Providern eingesetzt werden, die Ihnen Webspace mit freien CGI's zur Verfügung stellen (1und1, PureTec...). Es ist keine Konfiguration des Web-Servers notwendig! Die Sache ist sehr einfach:
1. Legen Sie unterhalb Ihres CGI-Verzeichnisses ein Verzeichnis "tdbengine" an.
2. Kopieren Sie in dieses Verzeichnis alle Dateien der tdbengine
3. Sorgen Sie dafür, dass folgende Dateien ausführbar sind: tdbengine, pdk.prg, scanfile.prg
Das war's auch schon. Wenn Ihre Domain beispielsweise "www.meinedomain.de" heisst ind Ihr CGI-Verzeichnis "cgi-bin", dann sollte jetzt der Aufruf von "http://www.meinedomain.de/cgi-bin/tdbengine/test.prg" das bekannte "Hello world!" in die Browser-Anzeige zaubern.
Hier noch ein Hinweis für Windows-Anwender: Das einfache Kopieren der Datein mittels FTP reicht nicht aus, da in den meisten Fällen derart transpotierte Dateien für alle anderen Anwender ausser dem User selbst nur lesbar sind. Aber nahezu alle bekannten FTP-Klienten können die Zugriffrechte ändern.
Das tdbSQL-Projekt
Thomas Friebel, ein Mitarbeiter der TDB-GmbH, hat das Projekt eines auf der tdbengine basierenden SQL-Servers initiiert und hurtig vorangetrieben. Unter http://tdbsql.sourceforge.net können Sie den aktuellen Stand des Projekt sehen. Mitarbeiter sind stets willkommen. Besonders spannend an diesem Projekt werden die Schnittstellen zu PHP, Perl und Java sein (gerade hier ist kompetente Mitarbeit gefragt).
Neue Möglichkeiten in der Konfiguration
Die Konfigurationsdatei wird (auf Unix-Systemen) nun in folgenden Verzeichnissen gesucht:
1. Im Verzeichnis, in dem sich das auszuführende Programm befindet
2. Im Verzeichnis, in dem sich die (ausführbare) tdbengine befindet
3. Im Verzeichnis /etc/tdbengine
Auf Windows-Systemen entfällt 3.
errorlog
In der tdbengine.ini kann nun auch der Pfad zur Fehler-Logdatei eingestellt werden:
[globals]
errorlog=/var/log/tdbengine/error_log
cdmode
Mit cdmode=1 in der Abteilung [globals] der tdbengine.ini kann festgelegt werden, dass sämtliche Tabellen im R/O-Modus geöffnet werden, auch wenn im Programm etwas anderes angegeben ist. Textdateien, die zum Schreiben geöffnet werden, werden automatisch zu Ramtexten.
Programminterne Kommunikation über Environment-Variablen
Es gibt nun zusätzlich zum Environment, das vom Betriebssystem zur Verfügung gestellt wird, zwei weitere Variablen, auf die innerhalb eines EASY-Programms zugegriffen werden kann:
TDB_VERSION
Die tdbengine liefert hier String der Form "6.2.9"
TDB_OS
Da gibt es derzeit zwei Antworten:
"unix" für FreeBSD und Linux
"win32" für Windows
Mit einer (bislang undokumentierten) Spezialform der Funktion GetEnv) kann man auch Variablen für das interne Environment der tdbengine setzen:
GetEnv('set:Varibale=Wert')
Beispiel: GetEnv('set:MEIN_NAME=Hans Mustermann')
In der Folge liefert GetEnv('MEIN_NAME') den String 'Hans Mustermann'. Diese Variable dann solange gültig, bis sie entweder umdefiniert oder aber die tdbengine beendet wird.
Zwei selbstdefinierte Environment-Variablen werden von der tdbengine selbst ausgewertet:
HTTP_PROXY
Der Inhalt dieser Variablen wird verwendet, wenn ein Template von einem entfernten Rechner via http geladen wird, also bei
LoadTemplate('http://...')
Ist die Variable HTTP_PROXY auf die IP-Adresse (oder bekannten Rechnernamen) gesetzt, so wird die Anfrage an diesen geleitet. Der Zugriff eines Web-Servers auf des Web über einen Proxy ist ein gängiges Verfahren, Sicherheitsrisiken zu minimieren.
TDB_SUBST
Diese Variable wird dann ausgewertet, wenn die tdbengine als Server läuft, also die Funktion Server() aktiv ist. In diesem Fall wird die Funktion CGIWriteTemplate() so erweitert, dass vor der Ausgabe des Templates sämtliche Ersetzungen durchgeführt werden, die in der Datei stehen, auf die TDB_SUBST verweist. Diese Datei ist zeilenweise so aufgebaut:
Target;Ersetzung
Statt langer Erklärungen hier ein Beispiel:
Angenommen wir haben folgendes Template:
<html>
<head>
<base href="http://www.tdb-engine.de/">
</head>
<body> <img src="http://www-tdb-engine.de/pics/einbild.jpg"> <h3>Herzlich Willkommen</h3> <a href="/scripts/anfang.prg">Zur Einleitung</a><br> <a href="/scripts/ende.prg">Zum Ende</a><hr>
</body>
</html>
Im aktuellen Verzeichnis gibt es eine Text-Datei 'local' mit folgendem Inhalt:
www.tdb-engine.de;localhost:3444
/scripts/;/cgi-tdb/local/
/anfang.prg";anfang.prg?query=start"
Nach GetEnv('set:HTTP_SUBST=local') gibt die tdbengine das obige Template (mit CGIWriteTemplate()) so aus:
<html>
<head>
<base href="http://localhost:3444/">
</head>
<body> <img src="http://localhost:3444/pics/einbild.jpg"> <h3>Herzlich Willkommen</h3> <a href="/cgi-tdb/local/anfang.prg?query=start">Zur Einleitung</a><br> <a href="/cgi-tdb/local/ende.prg">Zum Ende</a><hr>
</body>
</html>
Alles klar? Zugegeben, es ist kompliziert. Aber die Möglichkeit, die sich aus diesem Feature erschließt, ist einfach überwältigend: Sie können einen bestehenden Internetauftritt (mit dynamischen Inhalten, sonst wäre es ja langweilig) mit ganz wenigen Handgriffen so auf eine CD brennen, dass dieser ohne eine Änderung an den Programmen oder HTML-Seiten sofort von dieser CD läuft. Machen Sie das mal mit irgendeinem anderen Programm (PHP/MySQL, Perl ... )
Neue Funktionen
ReOpenDB
Es gilt ja die Regel, dass man eine Tabelle nur mit den unbedingt benötigten Rechten öffnen sollte. Manchmal kommt es aber vor, dass man ein Tabelle zum Lesen geöffnet hat, und nun will man in diese Tabelle schreiben. Also CloseDB() mit anschließendem OpenDB()? Diese Lösung hat den Nachteil, dass nach dem CloseDB() der alte Tabellenhandle nicht mehr gültig ist und der neu (nach OpenDB() ) nicht mehr mit dem alten übereinstimmen muss. Um das zu verhindern gibt es nun die Funktion ReOpenDB(), das den Tabellenhandle bewahrt und die Tabelle mit neuen Rechten wiederöffnet.
ReOpenDB(db : INTEGER; accessmode : INTEGER) : INTEGER
Zu den zulässigen accesmodes siehe OpenDB().
Ramtext
Ramtext(Filename : STRING; InitSize : INTEGER)
Normalerweise werden Ramtexte mit 16 KByte initialisiert (ausser wenn Sie bei der Erzeugung schon mehr Platz benötigen). Sie wachsen dann bei Bedarf ebenfalls in 16 KByte-Schritten. Mit der Funktion Ramtext() kann das geändert werden. Die Initialisierungsgröße kann z.B. gleich wesentlich größer eingestellt werden, damit die automatischen Inkremenierungsschritte unterbleiben, die bei sehr großen Ramtexten zu einem enormen Bedarf an Arbeitsspeicher führen können.
SetAlias
SetAlias(db : INTEGER; Alias : STRING) : INTEGER
Erzeugt einen weiteren Handle für eine bereits geöffnete Tabelle. Die Tabelle kann in SUB-Reports etc. uner dem Alias-Namen angesprochen werden. Die Alias-Tabelle hat einen eigenen Satzpuffer, eine eigene Markierungsliste und eine eigene Zugriffsverwaltung.
f_pos
Die Funktion f_pos() Liefert die aktuelle Position in einem Stream:
F_Pos(hdl : INTEGER) : INTEGER
Beispiel:
VAR hdl : INTEGER = F_Open('./test.prg',0)
VAR buf : BYTE[1000]
...
IF hdl>0 THEN F_Read(hdl,buf[0],10) CGIWriteLn(Str(F_Pos(hdl)) // ergibt 10
END
Unix-Timestamps
Unter einem Unix-Timestamp versteht man die Anzahl der Sekunden, die seit Beginn der Unix-Epoche am 1.1.1970 vergangen sind. Werden diese in einer 32-Bit Variablen gespeichert, so ist damit der Bereich von 1970 bis etwa Anfang 2038 abgedeckt. Unix-Timestamps eignen sich sehr gut, Update-Zeiten für Datensätze festzuhalten, wenn eine sekundengenaue Auflösung ausreicht (was in den meisten Fällen wohl zutrifft).
Konstanten vom Typ Unix-Timestamp werden in der Form
DD.MM.YYYY_hh:mm:ss
angegeben (DD = Tag, MM = Monat, YYYY = Jahr, hh = Stunden, mm = Minuten, ss = Sekunden). Wichtig ist hierbei der Unterstrich zwischen Datums- und Zeitangabe.
Folgende Funktionen stehen für Unix-Timestamps zur Verfügung:
| UNIX_NOW |
Liefert die aktuelle Systemzeit als Unix-Timestamp, also als Anzahl der Sekunden seit dem 1.1.1970 |
| DATETIME_TO_UNIX |
Berechnet den Unix-Tmestamp für eine Datums- und Uhrzeitkombination im TDB-Format |
| UNIX_DATE |
Liefert das Datum (im TDB-Format) aus einem Unix-Timestamp |
| UNIX_TIME |
Liefert die Zeit (im TDB-Format) aus einem Unix-Timestamp |
| UNIXTIME_TO_STR |
Konvertiert einen Unix-Timestamp in einen String |
| STR_TO_UNIXTIME |
Konvertiert einen String in einen Unix-Timestamp |
Zum Speichern von Unix-Timestamps gibt es den neuen Datentyp "UTIME", der eine 32-Bit-Zahl speichert. GetField() und SetField() konvertieren derartige Inhalte automatisch:
SetField(db,'edit_date','18.11.2003_14:12:52')
GetField(db,'edit_date') -> "18.11.2003_14:12:52"
Scheller wird es freilich, wenn auf Unix-Timestamps mit den Funktionen SetRField() und GetRField() zugegriffen wird.
SetRField(db,'edit_date',UNIX_NOW)
IF UNIX_NOW-GetRField(db,'edit_date')<3600 THEN ... // Datensatz wurde innerhalb der letzten Stunde editiert...
Erweiterungen bereits bekannter Funktionen
LoadTemplate via Proxy
Diese interne Erweiterung wurde bereits oben bei HTTP_PROXY erläutert.
f_open
Bisher wurden Streams (untypisierte Daten) mit f_open() immer im R/W-Modus geöffnet. Das kann manchmal lästig sein, in vielen Fällen ist es aber unnötig. Deshalb gibt es jetzt einen (optionalen) zusätzlichen Parameter, mit dem der Modus festgelegt wird.
Socket- und Streamfunktionen mit direkter Pufferindizierung
Die Funktionen f_read(), f_write(), getsock() und putsock() wurden so erweitert, dass beim Übertragungspuffer nun auch ein Feldindex angegeben werden kann:
VAR buf : CHAR[10000]
F_Read(hdl,buf[x],n) : INTEGER
F_Read(hdl,buf,n) = F_Read(hdl,buf[0],n) // WIE bisher
Das Server-Projekt
Die Funktion Server() ist nun auch in der Windows-Version verfügbar, allerdings hier nur als Single-Process-Server. Das sollte aber für die allermeisten Anwendungen keine gravierende Rolle spielen. Und weil diese Variante auch für Linux von Interesse sein kann, ist sie auch hier verfügbar:
Server(Port,Prozess,Maxconnections[,Modus]) : INTEGER
Port: TCP-Port für eingehende Verbindungen
Prozess : parameterlose EASY-Prozedur
Maxconnections : maximale Anzahl von Verbindungen (Sockets) für den Server
Modus : 0 (Vorgabe) -> Single-Process, 1 (nur Linux/FreeBSD) -> Multi-Process (forked)
Die Funktion liefert nur dann ein Ergebnis, wenn sie terminiert, was sie eigentlich nicht machen sollte. In diesem Fall ist das Funktionsergebnis der Fehlercode des Betriebssystems:
13: Öffnen des privilegierten Ports verboten
98: Port bereits belegt
Die Arbeitsweise:
Wenn Server() ausgeführt wird, wartet die tdbenine auf eingehende TCP-Verbindungen am angegeben Port. Wird eine Verbindung aufgebaut, so wird die angegebene Prozedur ausgeführt. Innerhalb dieser Prozedur sind zwei Handles verfügbar:
TextHandle 128
SocketHandle 128
Beide Handles können zur Kommunikation mit dem Klienten verwendet werden. Allerdings sollte man darauf achten, dass für das Lesen und Schreiben (bzw. Empfangen und Senden) nur jeweils eines der beiden Handles verwendet wird, vorzugsweise das Socket-Handle (weil Textoperationen immer gepuffert werden).
Ist die Funktion server aktiv, so werden alle CGI-Ausgaben (CGIWrite(), CGIWriteln(), CGIWriteTemplate()) auf dem Server-Socket ausgeführt.
Wenn die Prozedur beendet wird, wird die Verbindung zum Klienten beendet und das ganze Spiel beginnt von vorne.
Was kann man damit machen?
Ein Beispiel: Mini-Web-Server für Einzelplatz- und CD-Applikationen
Hierzu gibt es in Kürze eine eigene Beschreibung im Doku-Bereich.
Viel Erfolg mit der tdbengine wünscht
Ulrich Kern
|