Freie Tabellen

Die wesentlichen Neuerungen von Visual FoxPro sind die Objektorientierung und der Datenbankcontainer. All die vielen Verbesserungen von Visual FoxPro machten es leider notwendig, das Tabellenformat zu ändern.

FoxPro arbeitet zwar nach wie vor mit Tabellen im DBF-Format, aber diese sind nicht mehr kompatibel, sobald man einige der neuen Funktionen und Fähigkeiten benutzt. Aber auch ganz ohne Verwendung von sowohl Objektorientierung als auch des neuen Datenbankcontainers hat sich so einiges im Datenbankbereich getan.

Zuallererst müssen wir uns an eine neue Namenskonvention gewöhnen. Bisher war es durchaus üblich, DBF-Dateien als Datenbanken zu bezeichnen. Die Datei-Endung wurde ja schließlich als DataBaseFile übersetzt. Zukünftig spricht man bei DBF-Dateien nur noch von Tabellen, eine Datenbank ist nunmehr die Zusammenfassung mehrerer Tabellen zu einer logischen Sicht der Daten. Datenbanken haben die Endung DBC für DataBaseContainer. Tabellen, die nicht in eine Datenbank eingebunden sind, werden als „Freie Tabellen“ bezeichnet. Diese können im Format unserer bisherigen DBF-Dateien vorliegen oder als DBF-Dateien mit dem neuen Format für Visual FoxPro. Sofern man letzteres benutzt, hat man nachfolgende Vorteile und neuen Möglichkeiten:

Weniger Platzbedarf

Eine erste kleine Neuerung ist die Reduzierung des Speicherplatzbedarfs für Pointer. Die Feldarten MEMO und GENERAL benötigen wesentlich weniger Bytes als zuvor - nämlich nur 4 statt bisher 10. Der reduzierte Platzbedarf verkleinert Tabellen erheblich und reduziert somit Speicherplatzbedarf, Netzbelastung und Zugriffszeit.

Binäre Felder

Für die Feldarten Zeichenkette und Memofeld wurde jeweils eine zusätzliche Variante ohne Codepage-Konvertierung aufgeführt. Zum einen gibt es CHARACTER BINARY (Zeichen binär, wie Zeichen ohne Codepage) und MEMO BINARY (Memo binär, 4 Byte, wie Memo ohne Codepage). Durch diese Erweiterung kann auf den Befehl SET NOCPTRANS zukünftig verzichtet werden, man kann in solchen Feldern z.B. verschlüsselte Passwörter systemunabhängig abspeichern.

Neue numerische Feldarten

Außer numerischen Feldern und Fließkommazahlen gibt es zukünftig drei weitere Feldarten mit Zahlenwerten:

Die neuen numerischen Feldarten benötigen deutlich weniger Platz zum Abspeichern von großen Zahlen als die bisherigen numerischen Felder. Dies verkleinert Tabellen erheblich und reduziert ebenfalls Speicherplatzbedarf, Netzbelastung und Zugriffszeit.

Timestamp: Datum/Uhrzeit

Das neue Feld DATETIME ist eine Kombination aus Datum und Uhrzeit. Es wird mit 14 Zeichen Breite angezeigt, benötigt aber in der Tabelle nur 8 Byte wie ein normales Datumsfeld. Ich bezeichne es nachfolgend als TIMESTAMP. Dies ist aber nur bedingt korrekt, da es sich nicht um einen eindeutigen Zeitstempel handelt. DATETIME speichert nämlich nur volle Sekunden. Bei Type liefert es den Buchstaben „T“ zurück. Vier Umrechnungsfunktionen stehen für die neue Feldart zur Verfügung: TTOC() bzw. CTOT() (Time­stamp in Zeichenkette und zurück), TTOD() bzw. DTOT() (Timestamp in Datum und zurück).

Eine Reihe von Befehlen/Funktionen unterstützen die neue Feldart: DATETIME() liefert das aktu­elle Datum und Uhrzeit als Time­stamp zurück, SEC(), MINUTE() und HOUR() liefern den Sekunden-, Minuten- und Stunden-Anteil eines Timestamp. Mit WEEK() erhält man die Kalenderwoche und das Feld reagiert auch auf die Einstellung SET SECONDS zum Ein-/Ausschalten der Anzeige von Sekunden. Die tatsächliche Anzeige des Feldes wird von den Einstellungen SET DATE, SET CENTURY, SET MARK, SET HOURS und SET SECONDS beeinflußt. Diese kann man übrigens via SET SYSFORMATS aus den Windows-Systemeinstellungen übernehmen und lokal für jede Maske einstellen. Die Funktion WEEK() kann ansonsten auch auf normale Datumsfelder angewendet werden. Die benötigte Berechnungsart für die Kalenderwoche wird über SET FWEEK festgelegt.

Unterstützung von .NULL.

Zukünftig gibt es die neue Konstante .NULL., die das Nicht-Vorhandensein eines Wertes abbildet. Alle Feldarten können .NULL.-Werte enthalten. Dies gilt allerdings nicht für die neue Indexart CANDIDATE oder für zusammengesetzte Schlüssel. Die Befehle EMPTY() und ISBLANK() liefern für ein Feld mit dem Wert .NULL. ein .F. zurück, stattdessen muß man ISNULL() verwenden.

Doch betrachten wir einige Fälle mal etwas genauer, da das Konzept nicht vorhandener Werte doch etwas gewöhnungsbedürftig ist:

Die Konstante .NULL. kann z.B. beim REPLACE-Befehl verwendet werden. Im BROWSE-Fenster wird im Feld dann statt „0“ tatsächlich „.NULL.“ angezeigt. Ein Vergleich mit der Konstante hat jedoch immer das Resultat .NULL., unabhängig von dem tatsächlichen Feldwert. Ein COUNT FOR <Feldname> = .NULL. gibt also immer 0 zurück. Und nach dem Vergleich „lLogisch = (.NULL. = ‘Null’ ) “ hat die Variable „lLogisch“ zwar den Typ „L“ aber den Inhalt „.NULL.“ . Um Felder mit dem Wert .NULL. in LOCATE, COUNT usw. oder in Vergleichen verwenden zu können, muß man deshalb immer die Funktion ISNULL() verwenden (z.B.: „LOCATE FOR ISNULL (<Feld>)“ ).

Die Funktion NVL() entspricht der Konstruktion „IIF( ISNULL (<Feld1>), Feld2, Feld1 )“ und liefert von zwei Vergleichswerten immer denjenigen ungleich .NULL. zurück. Diese Funktion kann auch in SQL-Abfragen und Berechnungen verwendet werden. Der Befehl CALCULATE berücksichtigt übrigens bei Berechnungen keine Sätze mit .NULL.-Werten, und damit stimmt die Statistik endlich.

Mit SET NULL ON werden für alle Felder neu angelegter Tabellen NULL-Werte zugelassen, und man muß im MODI STRU-Dialog nicht alle Boxen selbst anklicken. Ein neues Feld, welches keine NULL-Werte unterstützt, kann man in eine Tabelle nicht ohne weiteres einfügen, wenn SET NULL ON ist. Beim Ändern der NULL-Unterstützung wandelt FoxPro .NULL.-Werte ggf. in „0“ oder „[ ]“ um.

Der SQL-Befehl ALTER TABLE erlaubt das programmgesteuerte Modifzieren von Tabellenstrukturen. Mit der Klausel „NULL“ bzw. „NOT NULL“ setzt man die .NULL.-Behandlung für die einzelnen Felder der Tabelle. Mit der zusätzlichen Klausel „NOVALIDATE“ kann man die normalen Prüfungen umgehen. Die gleiche „(NOT) NULL“-Klausel gibt es natürlich auch für CREATE TABLE.

Neue Indexart CANDIDATE

Die bisherigen „normalen“ Indizes haben unter Visual FoxPro zukünftig den Typ „REGULAR“. Das alte „UNIQUE“ gibt es weiterhin, aber zusätzlich gibt es davon eine verbesserte Variante mit der Bezeichnung „CANDIDATE“. Ein Index dieses Typs muß wirklich eindeutig sein, das Einfügen eines Datensatzes mit einem doppelten Schlüssel in die Tabelle führt zu einer Fehlermeldung. Die Indexart „CANDIDATE“ kann mit dem normalen INDEX-Befehl erzeugt werden. Die Indexart „UNIQUE“ wird zukünftig nur noch in Ausnahmefällen benötigt (z.B. Indizieren eines SQL-Cursors um ein DISTINCT-SQL einzusparen). In den SQL-Befehlen CREATE TABLE und ALTER TABLE heißt die neue Befehlsklausel zwar UNIQUE - diese bezieht sich aber immer auf CANDIDATE-Indizes und nicht auf die bisherigen UNIQUE-Indizes. Übrigens kann man mit der Funktion CANDIDATE() ganz einfach prüfen, ob es sich um einen solchen neuen Schlüssel handelt.

Hinweis: Gelöschte Datensätze werden bei CANDIDATE-Schlüsseln ebenfalls berücksichtigt. Möchte man in gelöschten Datensätzen Duplikate zulassen, muß eine FOR NOT DELETED()-Klausel verwendet werden. Damit die RUSHMORE-Optimierung trotzdem greift, sollte man das Feld zusätzlich mit einem REGULAR-Index versehen. Ein separates INDEX ON DELETED() TAG <DELETED> ist ansonsten nach wie vor von Vorteil.

SQL-Funktionen

Die SQL-Funktionen wurden mit neuen Befehlen und Erweiterungen abgerundet. Die neuen Befehle SQL-UPDATE und SQL-DELETE ähneln sehr stark dem bisherigen SQL-INSERT und dem normalen DELETE-Befehl von FoxPro und dienen zur Abrundung der SQL-Syntax. Wichtiger sind mir die Erhöhung des Befehlspuffers (auf ca. 6 KB) und der neue Befehl ALTER TABLE, der sehr umfangreich geworden ist. Der Befehl CREATE/ALTER TABLE hat eine mehrseitige Beschreibung im Handbuch. Allein eine Seite wird für die Syntax-Darstellung mit allen Klauseln benötigt. Davon stehen aber nur folgende bei „freien“ Tabellen zur Verfügung (Tabelle 1):

Befehl Beschreibung
ADD COLUMN Spalte in Tabelle einfügen
ALTER COLUMN Spalte in Tabelle ändern
DROP COLUMN Spalte aus Tabelle löschen
NULL / NOT NULL Null-Werte für Spalte ein-/ausschalten
NOCPTRANS Codepage-Konvertierung für Spalte ausschalten
UNIQUE Spalte wird CANDIDATE-Schlüssel
ADD (UNIQUE) TAG (CANDIDATE-) Schlüssel anlegen
DROP (UNIQUE) TAG (CANDIDATE-) Schlüssel löschen
RENAME COLUMN Spalte umbenennen
NOVALIDATE Validierung ausschalten (NULL-Werte)

Der Befehl ALTER TABLE kann hervorragend für Update-Programme verwendet werden und ist zwingend notwendig, um Datenbestände von Kunden bei der Auslieferung einer VFP-Applikation vor Ort ggf. automatisch zu konvertieren. Der Leistungsumfang des Befehls wird bei Verwendung des Datenbank-Containers mehr als verdoppelt!

Sonstige neue Befehle und Funktionen

Der Bereich Tabellen wurde außerdem um einen kleinen Satz von praktischen Funktionen ergänzt. Die nachfolgende Liste (Tabelle 2) ist nicht unbedingt vollständig, aber die enthaltenen Befehle sind ausgesprochen praktisch.
Befehl Beschreibung
ISEXCLUSIVE() Abfrage auf Exklusiv
(R)LOCK(„0“) Sperren Tabellen-Header
UNLOCK RECORD Freigeben einer Satzsperre
UNLOCK RECORD 0 Freigeben Tabellen-Header
Buffering-Funktionen Zwischenspeicherung von Datensätzen

Endlich ist man das Drama los, mühsam herausfinden zu müssen, ob eine Tabelle Exklusiv geöffnet wurde, und hat dafür eine Fertigfunktion - das war wirklich überfällig. Noch praktischer für den Multi-User-Betrieb aber ist die Aufhebemöglichkeit für einzelne Satzsperren statt bisher alle Sperren einer Tabelle auf einmal aufheben zu müssen (um dann ggf. mühsam einzelne Sätze erneut zu sperren).

Im ersten Moment weniger einleuchtend mag das Sperren und Entsperren des Tabellenheaders sein. Dadurch kann man aber verhindern, daß während eines Programmablaufs durch andere Anwender neue Datensätze angelegt werden können, ohne die Tabelle selbst für den Zugriff komplett sperren zu müssen.

Die Buffering-Funktionen werden zusammenhängend in einem eigenen Artikel behandelt, da sie thematisch gut zu den Transaktionen passen. Alle Buffering-Funktionen sind auch ohne Einsatz eines Datenbank-Containers verwendbar.

Die beiden Low-Level-Dateifunktionen FDATE() und FTIME() zur Abfrage von Datei-Datum und Datei-Uhrzeit ohne Umweg über ADIR() sind in der Dokumentation irgendwo als neu erwähnt, sie gab es aber schon unter FoxPro für Windows 2.6.

Codepage-Unterstützung

Die Internationalisierung ist bei Visual FoxPro weiter fortgeschritten. Folgende Befehle wurden mit einer AS-Klausel für die Angabe einer Codepage ergänzt: APPEND FROM, APPEND MEMO, COPY TO, EXPORT, IMPORT und MODIFY QUERY. Damit ist die „Bastelei“ mit dem CPZERO.PRG beim Importieren und Exportieren von Daten zwischen ASCII/ANSI endlich beendet. Der Befehl SET CPDIALOG mag trotzdem gelegentlich Verwendung finden.