Home

Benchmarks
Historie
Forum
Download
Helpware
Insider
Dokumentation
Kurs
Provider-Infos

Impressum



tdbengine - news vom 09.05.2001

Die Entwicklung an der tdbengine geht zwar langsam, aber kontinuierlich weiter. So gibt es in der Version 6.2.6 wieder viel Neues zu berichten:

Verbesserte Syntax und initialisierte Variablen

Nach wie vor besteht das dringende Bedürfnis, die Syntax von EASY einfacher und transparenter und leistungsfähiger zu machen.

VARDEF wird durch VAR ersetzt.

veraltet:
 
VARDEF x,y,z : STRING
VAR a = 'Hans'

jetzt:
 
VAR x,y,z : STRING
VAR a : STRING = 'Hans'

ebenfalls gültig:
 
VAR d,e,f : INTEGER = 1 // hier werden alle Variablen entsprechend initialisiert

Hierbei handelt sich um eine (eigentlich folgenschwere) Erweiterung. Denn initialisierte Variablen sind nunmehr auch global möglich. Die Initialisierung erfolgt unmittelbar nach dem Laden des Moduls. Wird ein Modul mittels "USES" eingebunden, so werden auch dessen globale Variable initialisert.

Beachten Sie bitte auch, dass die tdbengine (wenn nichts anderes angegeben ist) Variablen (auch Felder) immer initialisert:
 
Typ Initialierunswert
REAL 0.0
STRING ''
CHAR ASC(0)
BYTE 0
INTEGER 0
MARKS <leer>
TBITS 0

Allgemein lautet die Syntax:

Variablendeklaration::="VAR" Bezeichnerliste ":" Typ ["=" Ausdruck].

Der Ausdruck wird nicht zur Compilierzeit, sondern zur Laufzeit(!) berechnet und zugewiesen. Das bedeutet wiederum, dass hier auch selbstdefinierte Funktionen verwendet werden dürfen. Dazu ein Beispiel:
 
MODULE counter; //  location: lib/counter.mod

PROCEDURE Init : REAL;
VAR result, ec_before : INTEGER;
  ec_before:=getpara('ec'); setpara('ec 1');
  result:=opendb("database/counter/counter.dat","",0,15);
  setpara('ec '+str(ec_before));
  IF result=0 THEN
    cgiwriteln('content-type: text/html');
    cgiwriteln('');
    cgiwriteln('database-error: '+TDB_ErrorStr(TDB_LastError));
    HALT
  ELSE
    RETURN result;
  END
ENDPROC;

VAR db : INTEGER = Init;

Greift nun ein anderes Programm auf dieses Modul zu, so steht bereits nach

USES counter.mod;

mit counter.db ein gültiger (und zum Schreiben geöffneter) Tabellenhandle (der Tabelle database/counter/counter.dat) zur Verfügung.

Internes

Intern geht die tdbengine bei der Initialisierung von Variablen folgendermaßen vor:

Handelt es sich um lokale Variablen (die innerhalb einer Prozedure deklariert werden), so wird der Initialiserungscode genau an der Stelle aufgenommen, an der auch die Deklaration steht.

Beispiel:
 
PROCEDURE xyz;
  TueDiesUndDas 
  VAR a : STRING = 'hallo' 
  TueJenes
ENDPROC

Daraus macht die tdbengine:
 
PROCEDURE xyz;
VAR a : STRING
  TueDiesUndDas
  a:='hallo'
  TueJenes
ENDPROC

Bei einer globalen Variable wird indessen eine eigene Prozedur "_init" angelegt, in der sämtliche Initialisierungen für alle Module des Programms eingetragen werden. Diese Prozedur wird beim Start des Programms unmittelbar nach dem Laden (und damit vor "Main") ausgeführt.

Hinweis:

Aus Kompatibilitätsgründen wird die Syntax

VARDEF a,x,c : TYP
VAR x = exp

weiterhin unterstützt. Allerdings sollten Sie dazu übergehen, nur noch die neue Syntax zu verwenden.


Kommentare

Mit den (aus C bekannten) Zeichen /* ... */ lassen sich nun (nahezu) beliebige Textteile eines Programms als Kommentar kennzeichnen:
 
Module Kommentar_Test;

/* Modul zum Testen von Kommentaren,
   die über mehrere Zeilen gehen,
   wie dieser Kommentar hier */

/* Aber auch Kommentare innerhalb einer Zeile sind möglich: */

VAR i : INTEGER;
VAR max : INTEGER = 10000;

  WHILE i++<=max /* AND NOT ready */ DO
    // Hier ist ein anderer Kommentar bis zum Zeilenende
  END

Vorläufig gilt noch folgende Einschränkung: Kommentare dürfen nicht in Zeilen beginnen, die mit VAR oder PROCEDURE beginnen:

PROCEDURE xyz(i : INTEGER /*; s : STRING */ ) : INTEGER;  // ist nicht zulässig


Neue Datentypen

EASY kennt nun folgende neuen Datentypen für Variablen:
  • CHAR
  • BYTE
  • INTEGER
CHAR speichert genau ein Zeichen, ist ansonsten kompatibel zu STRING. Es gilt

VAR x : CHAR
VAR y : STRING

x:='A'  -> ASC(x) = 65
x:=''     -> ASC(x)  = 0  // Der Leerstring wird auf das Zeichen CHR(0) abgebildet
x:='ABC'  -> ASC(x) = 65 // es wird nur das erste Zeichen übernommen

Besonders interessant sind Felder vom Typ CHAR. Diese werden in der nächsten Version weitgehend kompatibel zum Typ STRING sein:

VAR x : CHAR[1000]

x:='Hallo Welt'  ->  x[0]:='H'; x[1]:='a'; x[2]:='l'; ...

BYTE speichert eine natürliche Zahl von 0 bis 255, ist ansonsten kompatibel zu REAL

Wiederum sind hier Felder vom Typ BYTE interessant:

VAR b : BYTE[10000]

Die Datentypen CHAR und BYTE (und vor allem Felder davon) werden erst in der nächsten Version wirklich nützlich, da sie dann als Ein- oder Ausgabepuffer für Datenströme (streams) Verwendung finden. Und darunter versteht die tdbengine dann beliebige Dateien und (Unix-)Sockets.

Bereits jetzt mit Vorteil einsetzbar ist der Datentyp INTEGER. Ein Variable von diesem Typ speichert eine ganze Zahl von -2147483648 bis +2147483647. Er sollte immer dann eingesetzt werden, wenn keine Kommstellen benötigt werden und der Zahlenbereich für die Variable ausreicht. Da alle Tabellenfunktionen intern mit solchen Größen arbeitet, ist INTEGER hier beispielsweise der Typ der Wahl:
 
VAR db : INTEGER;
..
db:=OpenDB('database/adressen/adress.dat');

INTEGER-Variablen können überall dort verwendet werden, wo auch REAL-Variablen erlaubt sind. Das gilt auch für Felder dieses Typs:
 
VAR marks : INTEGER[];
VAR db, i, fs, n : INTEGER;
...
IF db:=OpenDB('database/adressen/adress.dat') THEN
  fs:=FileSize(db);
  InitArray(marks[fs]);
  nLoop(i,fs-1,SEL(GetRField(db,'Status')<>3 OR marks[n]:=i+1, n++)) 
  // IF $Status=3 THEN marks[n]:=i+1; n++ END;
  PutMarks(db,marks)
END

Auch die Funktion InArray ist mit (eindimensionalen) INTEGER-Feldern erlaubt


Neue und erweiterte Funktionen

Grundsätzliche Erweiterung bei allen Index-Funktionen: Zu diesem Thema gibt es einen eigenen Artikel im Dokumentations-Menü. An dieser Stelle deshalb nur der Hinweis, dass alle Indexfunktionen jetzt wahlweise den Index-Namen oder die Index-Nummer verwenden können.

TreeInfo(db : INTEGER; index : INTEGER|STRING) : STRING

db : Tabellenhandle von OpenDB
index : Indexnummer oder Indexname (ohne Pfad)

Liefert die wichtigsten Informationen über den (einem Index zugrunde liegenden) B-Tree in der Form:

page=xxxx, n=xxxx, h=xxxx, p=xxxx, nn=xxxx
 
page Seitengröße in Bytes
n Ordnung (in jeder Seite befinden sich mindestens n Elemente; Ausnahme Wurzelseite)
h Höhe des Baumes (= Anzahl der Seiten, die maximal gelesen werden müssen, um einen Eintrag zu finden)
p Anzahl der (belegten) Seiten im Baum
nn Anzahl der Einträge im Baum

GetStructure(db : INTEGER; field : INTEGER|STRING) : STRING

db : TZabellenhandle von OpenDB
field : Feldnummer oder Feldbezeichner

Struktur des angegeben Feldes in Form:

Label,Typ,Spezifikation

Folgende Typen sind möglich:
 
Typ Spezifikation Bemerkung
STRING 1..255 Maximallänge des Strings
NUMBER 1 Byte
2 16-Bit-Integer
4 32-Bit-Integer
6,n Fließkomma mit (default) n Nachlommastellen (altes Format aus Kompatibilitätsgründen)
8,n Fließkomma mit (default) n Nachkommastellen: double precision
...,U Zusatzspezifikation für alle numerischen Typen zur Unterscheidung: 0 und keine Eingabe
MEMO Text beliebiger Länge
BLOB Binäre Daten
AUTO AUTO-Increment
DATE Datum
TIME Zeit
SELECT (Konstante_1,Konstante_2...) Auswahl (Aufzählung)
LINK Tabellenname ADL-Verknüpfung 1:n
REL ADL-Verknüpfung n:m

MarkDoubles(db : INTEGER; index : INTEGER|STRING) : INTEGER

db: Tabellenhandle von OpenDB
index: Indexnummer oder Indexname

Rückgabewert: Anzahl der doppelten Datensätze (bzgl. der Indexinformation)

Die Funktion funktioniert folgendermaßen: Die Tabelle wird in Reihenfolge des angegebenen Index untersucht. Liefert dabei ein Datensatz die gleiche Indexinformation wie sein Vorgänger, so wird er markiert.

Die Funktion ist sehr schnell, da nur Einträge aus der Indexdatei, nicht aber aus der Tabelle gelesen werden müssen.
 

DelMarkedRecords(db : INTEGER) : INTEGER

db : Tabellenhandle von OpenDB

Rückgabewert: Anzahl der gelöschten Datensätze

Mit dieser Funktion können recht schnell alle markierten Sätze einer Tabelle gelöscht werden.

Tritt beim Löschen ein Fehler auf, so wird ein Laufzeitfehler ausgelöst.
 

Reset, Rewrite und TAppend

Reset, Rewrite und TAppend dienen zum Öffnen von (internen und externen) Textdateien. Bisher wurden solche Dateien immer im ASCII-Zeichensatz gelesen und geschrieben. Bei ANSI-Dateien musste eine Stringkonvertierung mit OemToAnsi und AnsiToOem erfolgen.

Jetzt kann als zusätzlicher Parameter angegeben werden, ob es sich um eine ASCII- oder ANSI-Datei handelt.

0 : ANSI
1 . ASCII (Vorgabe)

Beispiel:
 
VAR t, i, db, x : INTEGER;
...
  t:=rewrite('export.txt',0); // ANSI
  readrec(db,x);
  nloop(i,maxlabel(db)-1,writeln(t,getfield(db,i+1)))
...

read(f : INTEGER [n : INTEGER | d : CHAR]) : STRING

Mit dem (optionalen) Parameter d ist es jetzt möglich, bis zu einem definierten Zeichen aus der Textdatei zu lesen (max. 255 Zeichen). Das Trennzeichen d selbst wird nicht zurückgeliefert:
 
read(t) =read(t,1) liest das nächste Zeichen aus der Textdatei t
read(t,n) 1<=n<=25 5 liest die nächsten n Zeichen aus der Textdatei
read(t,d) d : CHAR liest (maximal 255) Zeichen aus der Textdatei, bis entweder d gelesen oder das Ende der Datei erreicht wird


Verbesserungen

USES sucht nun auch im Verzeichnis des aufrufenden Programms.
GetIdent kann nun plattformübergreifend eingesetzt werden (Zeilenende mit CR/LF oder LF).
SetPara('nb 1') kann einen Performancegewinn von bis zu 25 % bringen.

Newsletter

Anmeldung zum Newsletter:
Name: 
Zusatz: 
EMail: