Session D-SQL

Client/Server mit dem
Microsoft SQL-Server

Peter Herzog
ProLib Software GmbH


Einleitung

Im Grunde genommen treffen hier zwei Welten aufeinander. Einerseits die Welt des „Flat-File-Models“ und die der Datenbank.

Es darf uns nicht täuschen, daß VFP seit der Version 3.0 bereits den Begriff der Datenbank verwendet. Visual FoxPro ist nach wie vor ein Desktop Datenbank System, welches immer noch mit einzelnen DBF-Dateien arbeitet. Bei dieser Definition sehen wir bereits, daß es sich bei der Datenbank eines SQL-Servers um etwas grundlegend anderes handeln muß.

Den Begriff der relationalen Datenbank hat 1970 E.F.Codd als erster eingeführt. Er hat damals einen Artikel veröffentlicht, der die Funktionsweise eines solchen Systems beschrieb und es auf die mathematischen Grundlagen der relationalen Algebra bezog.

Der letzte Abschnitt hört sich unter Studenten einer höheren Universität ganz toll an, für uns Pragmatiker hat dies jedoch keine Auswirkung auf unser Tun und Handeln, also werde ich im weiteren Verlauf solche hochtrabenden Wörter weglassen und einfach Vergleiche zu unserem VFP ziehen, um diverse Dinge zu erklären. Aber zumindest habe ich hiermit bewiesen, daß ich mir mein Wissen nicht aus den Fingern sauge, sondern ab und zu schon mal nachlese, wie etwas funktioniert, bzw. wie man gewisse Probleme lösen kann.

Zurück zum SQL-Server von Microsoft. Man sollte vielleicht bedenken, daß dieses Teil noch nicht sehr alt ist. Genau genommen wurde er ursprünglich von einem Dr. Epstein und einem Mark Hoffmann entwickelt. Besser bekannt als die Firma SYBASE, die ja noch heute existiert. 1987 war der erste SQL-Server verfügbar und hat zumindest aus der Basis der heutigen Systeme bestanden.

Man definiert ein Datenbanksystem unter folgenden Gesichtspunkten:

  1. logische Datenunabhängigkeit
  2. physikalische Datenunabhängigkeit
  3. prozedurale Schnittstellen
  4. effiziente Abarbeitung von Datenbankoperationen
  5. minimale Datenredundanz
  6. Datenintegrität
  7. konkurrierender Datenzugriff
  8. Datensicherheit
  9. Datenschutz

Wenn Sie die Liste so ansehen, dann finden Sie garantiert ein paar Stichwörter, die für Sie zutreffen werden, wenn Sie vorhaben einen SQL-Server einzusetzen.

Werden wir die Begriffe einmal auseinandernehmen und, wenn möglich, mit VFP vergleichen.

logische Datenunabhängigkeit

Darunter versteht man das Definieren von Views, also von logischen Ansichten. Beispiel: 2 Tabellen, Kunden und Orders. Ich definiere nun eine View auf die Felder Kundennummer, Name, Bestellnummer, Artikel, Menge, Preis.  Diese Ansicht meiner Daten stelle ich dem User als View zur Verfügung. Der User selbst hat keinen blassen Schimmer, daß es sich in Wirklichkeit um zwei verschiedene Tabellen handelt. Das können wir in VFP ebenfalls zur Verfügung stellen.

physikalische Datenunabhängigkeit

Das bedeutet, daß die Datensätze einer Tabelle nicht physikalisch sortiert sein müssen, um in einer bestimmten Reihenfolge gesehen zu werden. Dieser Begriff stammt also noch aus einer etwas älteren Periode der EDV. Jeder von uns weiß, daß es nichts leichteres gibt, als einen Index auf ein Feld zu machen um die Sortierung nach eigenen Wünschen zu gestalten. Es geht natürlich noch etwas weiter. Wenn wir in einem SQL-Befehl die Klausel „ORDER BY“ verwenden, dann hat sich die Engine darum zu kümmern, daß die Daten in der richtigen Sortierreihenfolge daher kommen. Selbst wenn kein Index von vornherein definiert wurde. In FoxPro (ohne Visual) war dies bereits möglich.

prozedurale Schnittstellen

Dies bedeutet, daß eine Schnittstelle zu einer Programmiersprache vorhanden sein muß um das Verhalten des SQL-Servers zu steuern. Wie beim SQL-Server so auch beim VFP, sind dies die Stored Procedures.

effiziente Abarbeitung von Datenbankoperationen

Was unter FoxPro als die Rushmore Optimierung bekannt geworden ist, soll auch in einem SQL-Server vorhanden sein, damit man selbst nichts mehr unternehmen muß um die Daten auf dem schnellsten Wege zu erhalten.

minimale Datenredundanz

Ein Begriff, der uns eigentlich als logisch erscheinen sollte. Gleiche Daten nicht mehrmals abspeichern.

Datenintegrität

Eine Datenbank muß erkennen, ob es sich um logisch richtige Daten handelt. Also Alter einer Person kann nicht negativ sein usw. Dies wird durch die Rules (Regeln) erledigt.

konkurrierender Datenzugriff

Das gute alte Sperrverhalten auf Datensätze ist angesprochen.

Datensicherheit

Dies ist ein Teil, wo der SQL-Server eindeutig die Nase vorne hat. Dazu aber später.

Die Definition soll bedeuten, daß die Daten selbst nach einem Software oder Hardwarefehler in dem Zustand wiederzufinden sind, wie vor der „Transaktion“.

Datenschutz

Auch hier wieder ein erheblicher Pluspunkt gegenüber VFP. Auf einem SQL-Server kommt man nur dann an die Daten heran, wenn man das Kennwort und Paßwort kennt.

Dies war nun die rein theoretische Seite der Datenbank. Wie Sie gesehen haben sind viele Teile bereits in VFP zu finden.

Nun kommen wir zur

Installation eines Microsoft SQL-Servers.

Genau genommen ist diese Prozedur auf das Einlegen einer CD und dem Aufruf des SETUP Programmes beschränkt. Im Detail liegen jedoch viele kleine Stolperfallen, auf die ich Sie hinweisen möchte.

Unter anderem werden Sie gefragt werden, welchen Netzwerksupport Sie verwenden wollen. Tragen Sie auf alle Fälle „NAMED PIPES“ ein, den dies ist der gebräuchlichste Weg um einem SQL-Server etwas zu sagen. Es funktioniert, naiv erklärt, wie ein Dateikanal. Benötigen Sie auch noch IPX oder TCP/IP, dann markieren Sie einfach diese Netzwerkunterstützung und schon werden die benötigten DLL´s mit auf Ihren Server kopiert. Wie Sie bemerkt haben, können mehrere Protokolle parallel verwendet werden. Nur beim Multiprotokoll sollten Sie vorsichtig sein, da es durch die fortwährende Abprüfung der Datenpakete zu den langsamsten zählt. Wenn Sie TCP/IP wählen, dann schlägt Ihnen der SQL-Server bereits den Default Port von 1433 vor. Aus dem Internet wissen wir, daß neben den normalen IP-Adressen auch noch die Portnummer eine Rolle spielt. Dies ist sozusagen die richtige Adresse innerhalb des Computers, wenn das Datenpaket übers Kabel heran rollt. Bei WWW-Servern ist z.B. 80 der Defaultport bei FTP die 21.

Es gibt nun noch weitere Einstellungsmöglichkeiten:

Der physikalische Pfad der Daten auf dem NT-Server, soll der SQL-Server gestartet werden, wenn NT-hochfährt ?, Executive und Mailsupport automatisch starten. (Dazu später), Character Set. Also welche „Codepage“ soll verwendet werden und die Sort Order der Indizes. Leider ist dies nur einmal für das gesamte System zu vergeben und nicht wie bei FoxPro für jede einzelne Datei.

Anschließend werden Sie noch gefragt ob der SQL-Server sich extra einloggen soll, als ob es ein User am NT-Server sei, oder ob es ein localer System Account sein soll, der keine speziellen Zugriffsrechte benötigt. Ich stelle hier immer localer System Account ein, ansonsten müsste ich bestimmen, welchem User der SQL-Server entspricht und diesem explizit wieder Rechte zuweisen. Siehe auch Trsuted Connection beim ODBC-Treiber.

Sie haben bemerkt, daß ich bereits davon gesprochen habe, daß Microsoft-NT hier eine gewichtige Rolle spielt. Im Gegensatz zu Oracle, Sybase usw. kann der Microsoft SQL-Server nur auf Windows-NT laufen. Hier sieht man auch schon, daß ein Server nicht unbedingt etwas mit Hardware zu tun haben muß. Im Falle vom SQL-Server handelt es sich um ein (etwas größeres) Programm welches auf dem Betriebssystem Windows NT installiert ist. NT selbst besteht im Grunde genommen nur aus einem Kernel, der nahezu dumm ist. Erst verschiedene Dienste, also Programme machen das Betriebssystem aus. Im Falle von NT gibt es dann noch den Workstationdienst, Serverdienst, Netzwerkdienst usw. Die werden natürlich automatisch installiert und kommunizieren direkt mit dem Kernel. Auch der SQL-Server spricht direkt mit dem Kernel und verwendet dessen Komponenten um auf Daten zuzugreifen usw.

Zurück zur Installation. Nach dem Ausfüllen aller Fragemasken wird die sogenannte MASTER.DAT aufgebaut. Dies ist eine Datenbank, welche die Systeminfos beinhaltet. Hier werden die Namen der einzelnen Datenbanken abgespeichert usw. Standardmäßig ist diese Datenbank 25 MB groß und sollte für die meisten Zwecke reichen. Vergrößern kann man diese immer noch.

Hier noch ein Hinweis zum Namen des NT-Servers. NT erlaubt auch Namen die einen Bindestrich beinhalten. Als Beispiel hieß mein NT-Server „HERZOG-NT“. Damit konnte ich natürlich überall arbeiten und hatte keine Probleme. Leider mag der SQL-Server diesen Namen nicht und weißt einem darauf beim Installieren hin. Man kann zwar den expliziten Namen des SQL-Servers im Nachhinein ändern, aber es stört bei der täglichen Arbeit.

Nachdem die Installation vollendet wurde, muß der SQL-Server gestartet werden. In der neu angelegten Programmmanager Gruppe finden Sie den SQL-Service Manager. Dieses Programm zeigt eine nette Verkehrsampel, die durch Rot, Gelb und Grün den Status des SQL-Servers anzeigt. Ein Doppelklick genügt und schon arbeitet der SQL-Server.

Gehen wir nun dazu über unseren SQL-Server zu verwalten. Dies können wir direkt am Server machen oder von einer Windows 95 / Windows NT Workstation aus. Wenn Sie das Setup Programm des SQL-Servers auf einer fremden Maschine aus machen, können Sie angeben, daß Sie nur die Client-Software installieren wollen. In diesem Falle werden alle benötigten Programme installiert und Sie können den SQL-Server aus der ferne Remote Fernwarten. Gerade dieser Punkt ist besonders wichtig, da ein SQL-Server Daten beinhalten kann, die absolut sicher sein müssen, also auch in einem feuersicheren Raum untergebracht sein müssen, usw.

Noch einmal zurück zum Netzwerksupport. Mit dem Client Configuration Utility können Sie Ihren Datenzugriff einstellen. Dort sehen Sie auch welche DLL verwendet wird, um übers Netz den SQL-Server zu erreichen. Im Falle von Named Pipes wird die DBNMPNTW.DLL verwendet.

Nun sind wir gerüstet um den SQL-Server das erste Mal so richtig live zu erleben. Starten wir deshalb den

SQL Enterprise Manager

Zuerst mal müssen wir den Server registrieren. Dazu werden Sie sowieso beim ersten Start aufgefordert. Registrieren deshalb, weil es ja möglich ist, mehrere Server parallel zu verwalten.

Tragen Sie nun Ihren Server ein und verwenden Sie die Standard Security. Als Kennwort tragen Sie SA (System Administrator) ohne Paßwort ein. Es fehlt nun noch ein Klick auf „Register“ und schon können Sie Ihren SQL-Server verwalten.

Der SQL-Server zeigt sich nun mit seinem dem Windows-Explorer verwandtem Bild.

Wir sehen bereits die einzelnen Teile des SQL-Servers.

Zwei Einzelheiten hatten wir noch nicht behandelt. Zum einen wäre das SQL Mail und zum anderen SQL Executive.

SQL Mail wird verwendet um Events, die selbst definiert werden können, einem Supervisor via Mail mitzuteilen. Als Beispiel könnte man das Unterschreiten eines Lagerbestandes hernehmen, daß auf dem Wege der E-Mail der Bestellabteilung mitgeteilt wird.

SQL Executive wird verwendet um SQL-basierende Aufgaben zu einem beliebigen Zeitpunkt auszuführen. Als Beispiel kann man das Anlegen eines Indizes anführen, daß dem Executive-Teil übergeben werden kann.

Um beide Dienste verwenden zu können müssen diese jedoch im bereits erwähnten SQL Service Manager (Ampelsteuerung) gestartet werden.

Database Devices

Jeder SQL-Server legt seine Daten in sogenannten Devices ab. Wenn man es genau nimmt ist ein Device eine Festplatte. Hier haben wir die Möglichkeit auf der NT-Server Festplatte mehrere Devices anzulegen. Physikalisch wird daraus eine .DAT Datei. Zum Beispiel ist die bereits erwähnte MASTER.DAT ein eigenes Device und deshalb auf dem Server als .DAT Datei zu finden.

Mit der rechten Maustaste gelangen Sie zu folgender Maske:

Hier sehen Sie wie ich ein Device anlege, welches 100 MB groß ist und auf dem E-Laufwerk unter \MSSQL\DATA\Test.DAT erzeugt werden soll. Bei „Create Now“ wird das Device sofort erzeugt. Ich kann es jedoch durch Schedule dem Executive überlassen, sofern dieser Dienst gestartet wurde.

Es gibt auch noch die Möglichkeit ein automatisches Mirrorring zu aktivieren, welches die gesamten Daten doppelt abspeichert.

Sollte uns das Device zu klein geraten sein, oder muß es aufgrund der Datenmenge vergrößert werden, so ist wiederum durch die rechte Maustaste ein Ändern möglich.

Achten Sie darauf, daß die Größe nur nach oben verändert werden kann. Sollten Sie ein Device zu groß angelegt haben, so müssen Sie es neu anlegen.

Ist dies nun erledigt sollte man sich überlegen, wie man seine Daten sichern möchte. Eine Datensicherung wird wiederum in einem Device angelegt, welches man unter „Backup Devices“ anlegen kann. Zwei Möglichkeiten haben Sie. 1. Ein Dumpdevice als Datei auf der Festplatte oder 2. eines als Tape-Sicherung auf einem Bandlaufwerk. Dumpdevices können beliebig groß und auch wieder kleiner werden.

Nun kommen wir zum eigentlichen Teil eines SQL-Servers, den

Datenbanken

Eine Datenbank wird in einem Device angelegt. Diese können auch beliebig vergrößert und verkleinert werden. Auch können mehrere Datenbanken in einem Device Platz finden. Ein rechter Mausklick läßt Ihnen wiederum die Möglichkeit, eine Datenbank zu erzeugen.

Hier sehen Sie, wie ich eine Datenbank mit dem Namen Test im Device Test anlege. Wichtig ist hierbei anzugeben, wo das sogenannte Transaction Log abgelegt werden soll.

Transaction Log

Dieser Teil eines SQL-Servers ist für die Sicherheit des gesamten Systems zuständig. Jeder SQL-Befehl wird hier protokolliert und so ist es möglich jede Aktion wieder nachzuvollziehen. Der Sinn der Sache ist folgender:

Beispiel: Am Monatsersten wird eine komplette Sicherung des SQL-Servers gemacht. Ab diesem Zeitpunkt hat man die Möglichkeit bei einem Crash des Systems auf diesen Zeitpunkt aufzusetzen. Die normale Sicherung bezieht sich nun nur noch auf das Transaction Log. Sollte der SuperGau eintreten, daß man Zurücksichern muß, dann kann man zuerst einmal die komplette Sicherung restaurieren. Von da an spielt man jedes Transaction Log jeder Teilmengensicherung zurück und läßt es quasi automatisch bis zum Zeitpunkt X vorwärtslaufen. Somit wird bis zur letzten Sicherung alles wieder nachgebaut. Sie werden vielleicht fragen, warum man nicht jeden Tag eine Vollsicherung macht. Dies ist ganz einfach zu erklären. 1. Für eine Vollsicherung muß der SQL-Server heruntergefahren werden. In Produktionsumgebungen nahezu unmöglich. 2. Wenn ein Device mehrere Gigabyte groß ist, dauert eine Sicherung eventuell länger als daß die Produktion still stehen darf.

Es sollte erwähnt werden, daß ein SQL-Server nicht nur für „kleine“ Datenmengen von 500 bis 1000 MB gedacht ist, sondern bis zu 7 Terrabyte verwalten kann.

Dieses Transactionlog muß immer wieder gesichert und dann gelöscht werden. Wenn Sie den SQL-Server einfach nur so in Betrieb nehmen, wird dieser bald nicht mehr arbeiten wollen, da genau dieses Log voll sein wird. Einer der häufigsten Probleme am Anfang einer SQL Administrator Laufbahn.

Wie Sie sehen, erzeuge ich das Transaktion Log in dem selben Device. Dies ist eigentlich nicht üblich. Normalerweise legt man ein eigenes Device an um die Datensicherheit zu erhöhen. Nur zu Testzwecken sollte dieser „Ausrutscher“ jedoch erlaubt sein.

Einigermaßen wichtig ist noch die Checkbox „Create for Load“. Dies bedeutet, daß die Datenbank nicht mit Hex-0 Zeichen gefüllt wird, sondern nur als logische Datei angelegt wird, um z.B.: eine Sicherung dort zurückzuspielen. Dieses Durchnullen kann bei großen Datenbanken auch mehrere Stunden dauern. Kürzlich legte ich eine 4 Gigabyte große Datenbank an und hatte dann den Rest des Tages „Urlaub“.

Wir sehen nun, daß zusätzlich zu den bereits bestehenden Datenbanken noch unsere Testdatenbank dazugekommen ist. Wir sehen auch, daß eine Unterteilung zwischen Groups/Users und Objects gemacht wurde. Wie bereits weiter oben erwähnt ist die Datensicherheit gegen unbefugten Zutritt ein oberstes Gebot. Deshalb kann man User bzw. Gruppen anlegen, welche bestimmte Rechte an den Daten haben können.

Direkt darunter verbergen sich die eigentlichen Teile einer Datenbank. Tabellen, Views, Stored Procedures, Rules und Defaults. Dies alles gibt es auch Visual FoxPro. Was hier noch zusätzlich eingebaut ist, sind die User Defined Datatypes. Dies ist sozusagen eine vordefinierter Variablentyp, welcher automatisch Default, Rules und dergleichen zugewiesen bekommt. Wenn dieser Datentyp in einer Tabelle verwendet wird, so werden die Rules, Default usw. nicht einzeln bei jedem Feld definiert, sondern nur einmal an dieser Stelle.

Tabellen

Wenn Sie eine neue Tabelle anlegen, werden Sie bemerken, daß es etwas mehr Datenfelder gibt, als in Visual FoxPro.

Ich habe hier einmal eine Aufstellung gemacht, mit welchem VFP-Datentyp, man welchen SQL-Datentyp erreicht.

Und schon fangen die Überraschungen an.

CHAR kann maximal 255 Byte umfassen.

BIT (also Logisch) ist nicht zu indizieren, da es wirklich nur einem einzigen BIT entspricht. Ein NULL-Wert ist natürlich dann auch nicht möglich.

Memos kann man zwar anlegen, haben aber eine extreme Angewohnheit. TEXT und IMAGE Felder können beliebig wachsen und es im vornhinein nicht vorhersagbar, wie groß diese Felder werden. Also wird am SQL-Server kurzerhand eine 2Kb Page für ein TEXT oder IMAGE Feld angelegt, sofern ein einziges Byte hineingeschrieben wird. Sollte das Feld auf NULL stehen, dann wird keine Page verwendet.

Lustige Rechnereien kann man da anstellen. Stellen wir uns eine Tabelle vor, mit 100 000 Datensätze. Davon 2 TEXT-Felder. In jedem TEXT / MEMO-Feld sind 10 Byte gespeichert. Die Datensatzlänge beträgt 100 Byte.

Einmal unter VFP betrachtet:

Und jetzt kommts..................Hier unter dem  SQL-Server:

Diese, mal 2048 Bytes ergibt 10 240 000 Bytes. Gerade mal ein bisschen mehr als bei VFP. Aber HALT. Nun zum Memoinhalt: 10 Byte pro Memofeld ergibt pro Datensatz eine Page pro TEXT-Feld. 2 TEXT-Felder * 2048 Byte * 100 000 Datensätze. Nicht nachrechnen. Es sind knallige 409 600 000 Byte ungefähr 409 MB gegenüber 12 bei VFP.

Als ich das erste Mal damit konfrontiert wurde, ging für mich eine Welt unter. Aber zumindest hatte der MS-SQL-Server dem Oracle etwas voraus. Bis zur Version 7 konnte Oracle nur ein TEXT-Feld pro Datensatz verwalten. Andererseit muß ich jetzt im Nachhinein sagen: „Und was bringts ??“

Was ich noch erklärungsmäßig noch unterschlagen habe, sind die IMAGE-Felder. Diese gibt es erst seit der Version 6.5 und entsprechen den GENERAL-Feldern. (OLE) Der Einsatz in großen Mengen ist jedoch aus oben genannten Gründen fraglich.

DATE und DATETIME werden identisch behandelt.

Allerdings gibt es hier auch eine Besonderheit. Der Datumsteil fängt als Integer beim 1.1.1900 zu rechnen an. Nach oben also 2 Milliarden und nach unten 2 Milliarden Tage Platz. Irgendjemand hat sich jedoch einfallen lassen, daß das kleinste Datum der 1. Januar 1753 und das größte Datum der 31.12.9999 sein soll.

Für Historiker die Flache Hand ins Gesicht. Die Franzosen werden sich freuen. Die Revolution hat es  gerade noch geschafft, abgespeichert zu werden. Abhilfe hier nur mit einem ins CHAR-Feld konvertierte Datum.

Views

VFP-Entwicklern ist dies kein Neuland mehr. Eine View ist nichts anderes als ein SELECT-Befehl. Genauso wie bei VFP können solche Views jedoch auch wieder beschrieben werden. Zu diesem Zweck wird ein UPDATE Kommando automatisch erzeugt.

Das schöne daran ist die Transparenz. Man kann sich eine View zusammenstellen, die aus x-beliebigen Tabellen beliebige Felder beinhalten kann. Der User bemerkt nicht, daß es sich um etwas spezielles handelt, sondern kann die Daten wie eine neue Tabelle ansprechen.

Stored Procedures

Unter VFP haben wir den gewaltigen Vorteil, puren FoxPro Code schreiben zu dürfen. Unter dem SQL-Server müssen Sie Transact-SQL verwenden. Eine Erweiterung des ANSI-Standards. Im SQL-Server sind bereits verschiedene Stored Procedures vordefiniert, die verschiedenste Aufgaben erledigen können. Als Beispiel sei sp_adduser angeführt mit dem man einen User programatisch eintragen kann.

In der Version 6.5 gibt es auch noch extended stored procedures, die entweder eine im SQL-Server eingebaute Funktion ode eine externe DLL ansprechen.

Rules

Unter Rules versteht man Regeln, wie die Daten auszusehen haben. Man kann der Datenbank Plausibilitäts-abprüfungen überlassen und kann sich sicher sein, daß keine falschen Daten in den Feldern landen.

NULL

Unter FoxPro gibt es seit vielen Jahren den Befehl Append blank. Er legt einen Datensatz an, der vollkommen Leer ist, also nichts enthält. Unter VFP wurde bereits der NULL-Wert definiert, der einmal aktiviert dafür sorgt, daß ein numerisches Feld nicht 0 und ein Character-feld nicht Blank erscheint, sondern eben als .NULL.

Das gleiche Verhalten haben wir beim SQL-Server. Wurde das Feld als NULL-fähig gekennzeichnet, dann wird bei einem leeren Datensatz ein .NULL. angelegt.

Ist ein Feld nicht als NULL-fähig angelegt, so gibt es Unterschiede zwischen VFP und SQL-Server. VFP legt dann ein Blank-Character und ein 0-Numerisch Feld an. Der SQL-Server bedankt sich mit einer Fehlermeldung, daß NULL-Werte nicht erlaubt seinen.

DEFAULTS

Eine Abhilfe gegen das NULL-Problem bietet uns der SQL-Server mit den Defaults. Wird ein Feld beim Datensatzanlegen nicht explizit gefüllt, dann wird der Default-Wert herangezogen.

Pagesize

Als es um die Berechnung des Plattenplatzes ging, erwähnte ich, daß alle Daten in Pages untergebracht werden. Die Größe einer Page beträgt 2048 Byte. Da mal hier ein Byte und mal da ein Byte für diverse Pointer verwendet wird, bleiben uns noch 2016 Byte übrig für Daten.

Rechnen wir eine Datensatzlänge von 37 Byte, so bekommen wir 2016 / 37 = 54 Datensätze. Der Rest von 18 Bytes sind verloren. Schlimm wird es wenn die Länge eines Datensatze 1009 Byte beträgt, dann paßt nämlich nur ein Datensatz in eine Page und der Rest muß leer bleiben.

Die Berechnung einer Datensatzlänge ist bereits ein Erlebnis. Ich verweise die Kopfrechner hierbei an die Handbücher.

Die Pages haben noch eine andere Eigenschaft, die man beachten sollte. Ein SQL-Server ist nur in der Lage eine gesamte Page zu sperren. Sperren wir also einen Datensatz, sind unter Umständen 54 andere ebenfalls gesperrt.

Der SQL-Server geht sogar so weit, daß er mitzählt, wie viele Prozent der Tabelle bereits gesperrt sind. Ab einem einstellbaren Level zahlt es sich nicht aus, so viele Datensätze einzeln zu sperren. Also sperren wir die gesamte Tabelle.

Indizes

Mit einem Index sortiert es sich besser, daß wissen wir schon lange. Natürlich kann auch der SQL-Server Indizes verwalten.

Zwei Typen stehen zur Verfügung. CLUSTERED und NON CLUSTERED. Ein clustered Index hat die Eigenheit, sich automatisch selbst zu sortieren. Und zwar in der echten physikalischen Reihenfolge. Lesezugriffe sind hier natürlich heftig schnell, aber ein Schreiben der Daten wirkt sich negativ aus. Diese Art von Index ist für statische Daten sehr gut geeignet. Sie müssen unter Umständen selbst ausprobieren, wann ein clustered index besser zu verwenden ist, als ein non clustered.

Es können natürlich auch mehrere Felder zusammengefasst werden um einen Index zu bilden.

Ein Index wird aus Leaves und Nodes gebildet, deren Erklärung ich mir jetzt spare, da es zu theoretisch wird. Aber speziell zu clustered Indizes und das Pagelocking ist es Wert, die betreffenden Stellen im Handbuch nachzulesen.

Wir müssen immer daran denken, daß auch Indizes in Pages untergebracht werden müssen. Indizes sind noch kleinere Einheiten als Datensätze. Also ist das Sperrverhalten noch extremer.

Achten Sie darauf, daß ein Transaktion Log mitgeführt wird, sobald ein Index an der Tabelle angelegt wurde. Auch der SELECT-Befehl wird beeinflußt. Ohne Angabe der ORDER-BY-Klausel wird automatisch nach dem ersten Index sortiert, ausgegeben.

Trigger

Der Abzugshebel am Revolver, genau genommen. Daher auch der amerikanische Ausdruck, „when the trigger fires“. Also wenn der Abzugsheben durchgedrückt wird, knallts. Oder in unserem Fall, eine Aktion wird ausgelöst.

Es gibt drei Aktionen bei denen es „knallen“ kann. Beim INSERT, UPDATE und beim DELETE. Damit läßt sich hervorragend Referentielle Integrität erzeugen. Aber das ist uns ja nichts neues mehr, seit VFP 3.0.

Den Server konfigurieren

Unter dem Menüpunkt SERVER / SQL Server / Configure können die globalen Einstellungen getätigt werden.

Hier die wichtigsten Teile:

Fill factor: Hier können Sie angeben wie voll eine Page mit Indizen angefüllt werden darf, bevor eine neue Page angefangen wird.

LE threshold maximum: Nach wievielen Pagelocks wird die gesamte Tabelle gesperrt.

LE threshold percent: Nach wie vielen Prozent gesperrter Pages der Tabelle wird die gesamte Tabelle gesperrt.

locks: Wie viele Locks sind am Server parallel möglich. 32 Byte pro Lock werden verbraucht.

memory: Wie viel Speicher (in 2 Kb Sprüngen) sollen verwendet werden.

open databases: Wie viele Datenbanken dürfen offen sein.

open objects: Wie viele Datenbankobjecte dürfen zu gleichen Zeit offen sein. (Tabellen, Indizes usw.)70 Byte pro Object.

user connections: Wie viele gleichzeitig offene Connections sind möglich. Besonders wichtig in Verbindung mit VFP

Wenn Sie diese Parameter richtig gesetzt haben, dann sollte nichts mehr schiefgehen. Die meisten sind bereits brauchbar eingestellt. Bei den user connections sind 5 warscheinlich zu wenig.

Achtung: Ich selbst machte die Erfahrung, daß die Maximalanzahl von user connections nicht immer einstellbar ist. Der SQL-Server benötigt dann nämlich mehr memory. Dieses lässt sich auch einstellen. Wird jedoch mehr eingestellt, als tatsächlich vorhanden ist, so lässt sich der SQL-Server nicht mehr starten. Eine Neuinstallation bzw. Neuerstellung der MASTER.DAT hat dies wieder behoben, wobei mir alle Daten verloren gingen.

Der Erklärungsteil des SQL-Servers ist nun beendet. Auf Replication und Publishing gehe ich nicht gesondert ein, da dies mit VFP nichts zu tun hat und dies ohnehin in einer anderen Session detailliert dargestellt wird.

ODBC

Als Zwischenstück zwischen VFP und dem SQL-Server dient uns der ODBC-Manager mit seinen ODBC-Treibern.

Der Zugriff auf den SQL-Server geschieht unter VFP generell nur über den ODBC-Treiber. Sie finden den dazugehörigen Manager in der Systemsteuerung.

Uns soll das Testbeispiel PUBS (bei der deutschen Version VERLEGER) dabei als Beispiel dienen.

Wenn Sie den ODBC-Manager aufrufen, bekommen Sie beim Klick auf ADD oder Hinzufügen eine Auswahl an installierten Treibern. Suchen Sie sich den Treiber für den SQL Server aus.

Im Data Source Name tragen Sie einen x-beliebigen Namen ein. Er sollte natürlich etwas mit der Datenbank zu tun haben, die Sie ansprechen wollen.

Unter Description können Sie diesen auch noch näher beschreiben.

Unter Server tragen Sie den Namen des SQL-Servers ein.

Bei Network Library kann es notwendig sein, den DLL-Namen einzutragen, der für die Übertragung zum Server benötigt wird. Den Namen bekommen Sie aus dem weiter oben bereits erwähnten Client Configuartion Utility. Dazu gehört unter Umständen auch die Network Address. Normalerweise bleiben diese Felder auf (Default).

Use Trusted Connection bedeuted, daß der Login-Name und das Paßwort des Systems verwendet wird, mit dem Sie sich in Ihrem Netzwerk eingetragen haben. Diese Option muß natürlich auch am SQL-Server eingestellt werden. Unter Umständen kann es sein, daß Sie nicht ordentlich identifiziert werden können, da mehrere Server und / oder Domänen im Netzwerk vorhanden sind und Sie an mehreren Servern gleichzeitig unter verschiedenen Namen Namen angemeldet sind. In diesem Falle schalten Sie Trusted Connections aus und verwenden Sie ganz normale Logins, die am SQL-Server angelegt wurden.

Database Name. Hier tragen Sie am besten gleich Ihre Datenbank ein, die Sie verwendet wollen. Dann brauchen Sie die Datenbank nicht mehr extra auszuwählen, wenn Sie auf den SQL-Server zugreifen. Als Beispiel tragen Sie gleich mal PUBS ein.

Language Name immer auf (Default) belassen. Ich habe bisher sowieso noch nie eine andere Sprach-DLL als die englische gefunden.

Generate Stored Prozedure for Prepared Statement. Dies bedeuted, daß Befehle in SQL-Sprache immer schon beim Übertragen compiliert werden. Andernfalls werden die Stored Procedures erst dann compiliert, wenn sie auch angesprochen werden.

Translation immer weglassen. Bisher musste ich immer feststellen, daß sich Fehler einsachleichen, sobald der Wert geändert wird.

Convert OEM to ANSI characters macht sich natürlich immer gut, damit man seine Umlaute auch wiederfindet.

Sobald Sie dies nun abspeichern, steht uns nichts mehr im Wege VFP auf unseren SQL-Server loszulassen.

Der Zugriff auf den SQL-Server

Wir haben zwei Möglichkeiten auf den SQL-Server zuzugreifen. Einerseits pur programatisch als SQL-Pass-Through und andererseits elegant über sogenannte Remote-Views.

SQL-Pass-Through

Dies ist der Weg, über den wir dem SQL-Server alles sagen können was wir wollen. Der Zugriff auf den SQL-Sever geschieht immer über Zeichenketten. Das was wir erhalten, ist immer ein Cursor.

Um mit dem SQL-Server „sprechen“ zu können, müssen wir uns zu erkennen geben. Dazu verwendet wir den Befehl SQLCONNECT(Datasource, Kennwort, Passwort, | Verbindung).

Datasource ist uns nun klar. Diese haben wir ja gerade eben im ODBC-Manager angelegt. Kennwort und Passwort muß natürlich bekannt sein. Bei einem neuinstallierten SQL-Server ist das Hauptkennwort „SA“ ohne Passwort.

Verbindung ist optional. Hier kann man eine Verbindung (connection) angeben, die man vorher in einer VFP-Datenbank angelegt hat.

Als Return-Wert erhalten wir das Ergebnis der Aktion. Dies ist gleichzeitig eine Art handle als ob es sich um einen Datenkanal zu einer physischen Datei handeln würde. Speichern sie diesen Wert ab, er wird benötigt um die Verbindung wieder abzubauen, bzw. überhaupt Daten zu schicken..

Eine Zahl größer 0 ergibt ein positives Ergebnis. Eine -2 gibt an, daß die Verbindung zwar keine Fehler produzierte, jedoch nicht zustande kam. Zum Glück kommt so ein Ereignis so gut wie nie vor, da Sie bei einem Fehler eine -1 und eine Fehlermeldung erhalten.

Mit =SQLEXEC(handle,Befehl, Return-Cursor) kann ich dem SQL-Server sagen, was ich vorhabe.

Der Befehl muß in Transact-SQL-Sprache formuliert worden sein. Der Returncursor gibt an, wo die Daten abgelegt werden sollen, wenn etwas zurückgeschickt wird.

Remote-Views

Die Remoteviews sind die elegante Version des Datenzugriffes. Als erstes wird eine normale VFP-Datenbank benötigt um die Definition der Remote-View aufzunehmen.

Sobald Sie die Datenbank geöffnet haben, können Sie über den Datenbankeditor oder programmatisch über CREATE SQL VIEW REMOTE eine externe View erzeugen.

Das erste was Sie zu Gesicht bekommen ist die Frage nach der Connection bzw. Verbindung. Sie haben zwei Möglichkeiten.

Die erste ist die Verwendung der im ODBC-Manager definierten Verbindung. (Available data source) Hier werden alle im ODBC-Manager eingetragenen Datasources aufgelistet. Wenn Sie diese Verbindung wählen, werden Sie nach Passwort und Kennwort jedesmal gefragt, wenn Sie diese Connection benutzen.

Eine elegantere Art ist die Verwendung von „Connections“.

Gegenüber der alten Version in VFP 3.0 sind hier die Einstellungen Database und Packet size dazugekommen. Nun ist es auch möglich, die Verbindung zu testen und wenn nötig eine neue anzulegen.

Datasource, Userid, Password und Database sollten nun bereits alt bekannte Begriffe sein. Es gibt jedoch noch weitere Einstellungen, die wichtig für die Arbeit sind.

Asynchronous execution: Dies bedeutet, daß VFP weiterläuft wenn es ein Kommando an den SQL-Server abgeschickt hat und nicht auf ein Ergebnis zu warten hat. Dies ist eine Art der Programmierung, die nicht besonders leicht zu handhaben ist, da man selbst immer wieder nachfragen muß, ob bereits Daten zur Verfügung stehen.

Display warnings: Zeige Warnungen und Fehler an, die nicht vom Programm abgefangen werden können.

Batch processing: Es ist manchmal notwendig dem SQL-Server gleichzeitig mehrere Aufgaben zu geben. Hier wird angegeben, daß dies Möglich sein soll. Wie bei der Asynchronous execution muß man jedoch selbst darauf achten, wan welche Daten abzuholen sind.

Automatic transaction: Gibt an, daß transactions automatisch von VFP verwaltet werden sollen. Im schlechtesten Fall bedeutet dieses, daß jedes INSERT, UPDATE und DELETE Statement in eine Transaktion gehüllt wird.

Packet size: Gibt die Paketgröße des Netzwerktransfers an

Connection (sec): Wieviele Sekunden soll gewartet werden, bis eine Verbindung als abgebrochen gilt ?

Idle (min): Nach wie vielen Minuten soll eine Verbindung automatisch abgebrochen werden, wenn Sie nicht aktiv ist ?

Query (sec): Nach wie vielen Sekunden wird eine Abfrage als abgebrochen betrachtet ?

Wait time (ms): Nach wie vielen Millisekunden wird gewartet, bis VFP einen SQL-String als vom SQL-Server angenommen ansieht?

Achtung: Bei langsamen Verbindungen (WAN, Telefon)  kommt es sehr schnell zu Wartezeiten, die die Default-Einstellungen um ein Vielfaches übertreffen können. Selbst in einem hochfrequentiertem Netz kann es bereits zu Zeitüberschreitungen kommen. Versuchen Sie durch Ausprobieren, den richtigen Wert einzustellen.

Nach all diesen Einstellungen speichern Sie die Connection ab und Sie erhalten eine Liste aller Tabellen auf der gewählten Datenbank.

Im obigen Beispiel sehen Sie den Inhalt der Pubs-Datenbank, (deutsch Verleger) in der Buchauthoren und deren Werke abgespeichert sind. Der Button Add fügt die angewählte Tabelle zur Remoteansicht hinzu.

Das was Sie hier einstellen können ist unter dem Strich betrachtet nichts anderes als einen SQL-String. Sie können sich diesen SQL-String auch betrachten. Im Menü oder über die rechte Maustaste steht Ihnen diese Möglichkeit zur Verfügung.

Der SQL-String der oben gezeigten Abfrage: SELECT * FROM dbo.authors Authors

Den SQL-Befehl abschicken können Sie ebenfalls über das Menü, der Toolbar oder rechten Maustaste. Sobald Sie die Abfrage ausführen, wird Ihnen sofort das Ergebnis geliefert.

Das was Sie nun sehen sind alle Datensätze der Tabelle Authors in der Beispieldatenbank PUBS.

Beachten Sie daß dies alle Datensätze sind. Es sind eben nicht mehr vorhanden. Ein SQL-Server hat aber die Möglichkeit beliebig viele Datensätze in eine Tabelle zu packen.  Und da erkennen wir bereits den großen Unterschied zu VFP. Wenn wir unter VFP eine Tabelle mit Browse anzeigen lassen, so sehen wir genausoviele wie eben Platz haben im Fenster. Sobald dieser Platz ausgefüllt ist, hört VFP auf Datensätze zu laden.

Wenn Sie allerdings einen SQL-Befehl verwenden der keinerlei WHERE-Klausel beinhaltet, dann schickt der SQL-Server unter Umständen 1 Million Datensätze herüber. Das ein „über die Leitung schicken“ Zeit braucht ist uns auch klar. Versuchen Sie es einmal mit einer großen Tabelle. Von mehreren Sekunden bis zu vielen Minuten kann es dauern, bis die Daten auf Ihrem Computer ankommen.

Das was wir sehen ist nämlich nicht die physische Tabelle der Daten, sondern eben nur eine Ansicht auf ein Datengrab und dieses wird zuerst einmal auf die eigene Maschine übertragen. Also TMP-Datei kann es dann angezeigt werden.

Um die Datenmenge einzuschränken haben wir nun mehrere Möglichkeiten. Zuallererst sollte man immer eine Filterbedingung angeben, also eine WHERE-Bedingung erzeugen. Dies ist mit dem View-Designer ein leichtes Ding. Unter der Page „Filter“ können Sie die Datenfelder auswählen und die Bedingungen angeben.

Ein kleiner Trick ist dabei, wenn man die View parametrisieren möchte, daß heißt, wenn man später festlegen möchte, wie der Filter aussehen soll. Dazu kann man mit einem führendem Fragezeichen eine Variable oder ein anderes Datenfeld angeben. Im Zeitpunkt des SQL-Abschickens wird dieser dort gefundene Wert als Filterausdruck eingefügt.

Weiters haben Sie die Möglichkeit „Joins“ als Verknüpfungen mit anderen Tabellen zu definieren. Weiters dürfen die Klauseln „ORDER BY“ und „GROUP BY“ nicht fehlen.

Unter der Page „Update Criteria“ finden wir nun den wichtigsten Teil einer Remote View. Wir wollen ja nicht nur Daten lesen sondern auch schreiben oder löschen.

Auffällig sind die Haken unter dem Schlüssel- und dem Bleistiftsymbol. Diese geben einerseits an, welches Feld den Schlüsselbegriff darstellt und andererseits, welches Feld geändert werden darf. Dies ist jedoch noch nicht alles. Es muß auch noch „Send SQL updates“ angeklickt werden. Ansonsten können Sie zwar im Grid editieren, es schlägt sich aber nicht auf den SQL-Server durch.

Wenn Sie einen neuen Schlüsselbegriff eingeben wollen, dann beachten Sie, daß der Bleistift-haken neben dem Schlüssel ebenfalls angeklickt ist.

Besonders interessant wird es bei der „SQL WHERE clause“. Es stehen vier Optionen zur Verfügung um den richtigen Datensatz wieder zu finden, um Änderungen zurückzuschreiben.

Key fields only: Wenn es sich beim Index der Tabelle um einen eindeutigen handelt, so genügt der Schlüsselbegriff um den Datensatz updaten zu können.

Key and updateable fields: Ein extremer Fall der das Update-Kommando an den SQL-Server extrem lang macht. Es wird nämlich zusätzlich zum Schlüsselbegriff auch noch jedes änderbare Feld mit in die WHERE-Klausel übernommen. Ich rate ab, diese Einstellung zu verwenden.

Key and modified fields: Ähnlich dem „Key and updateable fields“ wird auch hier die WHERE-Klausel erweitert. Jedoch nur mit den Feldern, die auch wirklich geändert wurden. Im schlimmsten Falle wiederum alle.

Key and timestamp: Am SQL-Server gibt es einen bestimmten Feldtypen, das timestamp-field. Pro Datensatz darf es nur eines geben und dioes wird exclusiv vom SQL-Server selbst gefüllt. Sobald Sie solch ein Feld im Datensatz angelegt haben, können Sie dieses timestamp als echt eindeutiges Kennzeichen hernehmen, um den Datensatz zu identifizieren.

Dies ist mein Vorschlag, wie Sie Ihre Daten verwalten sollten.

Wir nehmen einmal ein etwas krasses Beispiel:

Eine Tabelle mit einem Feld. In dieser Tabelle sind 10 Datensätze welche alle den String „SQL“ beinhalten. Diese Tabelle lassen wir uns mittels Remote View anzeigen und Ändern nun am 3ten Datensatz den String auf VFP.

Für den SQL-Server gibt es keine Datensatznummern. Allein mit der „Key and timestamp“ Einstellung wird der richtige Datensatz gefunden, da ein Timestamp immer eindeutig ist.

Auf unserer Page gibt es nun nur noch eine Einstellung. Sie können entweder den UPDATE-Befehl verwenden oder per DELETE und INSERT eine Änderung der Daten hervorrufen. Manche Datenbanken verstehen den UPDATE-Befehl nicht, deshalb diese Option.

Nun haben wir alle Vorraussetzungen um auf Daten des SQL-Servers zuzugreifen. Sobald Sie die View abspeichern können Sie auf die Daten zugreifen, sobald Sie die View, wie eine Tabelle mit USE öffnen. Auch in einer Form in der Datasession fühlt sich die View wohl.

Achten Sie darauf, daß ein APPEND BLANK in einer View eventuell .NULL. Werte in einem Datensatz erzeugen kann. Wenn die Felder der Tabelle keine .NULL.-Werte zulassen, erhalten Sie eine Fehlermeldung.

Gleich zum Thema Fehlermeldungen. Fragen Sie beim Auftreten eines Fehlers mittels =AERROR() nach, welche Fehler aufgetreten sind. Mit AERROR() erhalten Sie ein Array. Denn beim SQL-Server können mehrere Fehler gleichzeitig auftreten.

Leider bleibt die Zeit nie stehen und so werden sich Daten auf dem SQL-Server verändern, wärend Sie diese in welcher Form auch immer betrachten. Um die Daten zu erneuern, die Sie lokal auf der Festplatte haben, verwenden Sie den Befehl =REQUERY().

Advanced Options

Unter dem Menüpad Query verbirgt sich ein äußerst wichtiger Menüpunkt namens „Advanced options“. Hier haben Sie die Möglichkeit Ihre View genauer zu tunen.

Folgende Einstellungsmöglichkeiten:

Share Connection

Diese unscheinbare Checkbox hat extreme Auswirkungen auf den SQL-Server. Um „Background-Data-fetching“ ausführen zu können muß jede View Ihre eigene Connection zum SQL-Server aufbauen. Wenn jede Datei so ausgerüstet wird und 20 Tabellen im Programm geöffnet werden, so hat ein SQL-Server bei 50 Usern bereits 1000 Connections zu verwalten, was jeden SQL-Server in die Knie zwingen wird. Jede Connection nutzt die mltithreading Eigenschaften des NT-Systems aus und wird Ihren SQL-Server totlegen.

Wenn Sie zulassen, daß Connections geshared (geteilt) werden, so müssen die Daten nacheinander ans VFP übertragen werden. Aber der SQL-Server wird nicht überfordert.

Number of  Records to Fetch at a time

Dies hat mit dem Background-Data-fetching zu tun, welches nicht wartet bis alle Daten einer Abfrage herübergekommen sind, sondern die eingestellte Anzahl dem User anzeigt und dann im Hintergrund schön langsam weiterliest. Allerdings ergeben sich hier ebenfalls extreme Probleme, da ein Count auf diese Menge erst dann stimmen wird, wenn alle Daten angekommen sind. Ein Go Bottom läßt alle Daten sofort übertragen.

Maximum number of records to fetch

Jede WHERE-Klausel ist nur so gut, wie die Datenmenge die in Wirklichkeit dahinter liegt. Eine Adresseinschränkung auf den Ort „Berlin“ wird zwar eine Datenmenge einschränken, aber wenn man dabei alle dort lebenden Personen überträgt, dann werden wieder mehr als nur 100 Datensätze werden. Wenn es nicht unbedingt notwendig ist, alle Daten zu übertragen, so können Sie hier die endgültige Datenanzahl einstellen.

Use Memo when character field length >=

Hier kann man angeben, daß anstelle eines Character-Feldes ein Memofeld verwendet werden soll, wenn eine bestimmte Länge überschritten wird.

Number of  Records to Batch Update

Hier kann angegeben werden wie viele Datensätze gleichzeitig geändert werden können. Dies entspricht einem NEXT x beim Replace-Befehl

Fetch memo

Hier kann angegeben werden, ob Memofelder übertragen werden sollen.

include memo fields in where clause

Abhängig von der Update Where Einstellung kann es vorkommen, daß auch ein Memofeld zum Suchen des richtigen Datensatzes verwendet werden kann.

Precompile SQL on backend server

SQL-Befehle werden „on the fly“ kompiliert, bevor diese ausgeführt werden. Hier kann angegeben werden, daß bereits beim ersten mal dieses Statement am Server gespeichert werden soll, um die zukünftigen Abfragen zu  beschleunigen.

Zum Abschluß

Für einen verwöhnten FoxPro-Entwickler ist der Einsatz eines SQL-Servers ein Schock. Vieles geht einfach nicht so wie man es gerne möchte und die Performance ist gegenüber dem Fuchs als „mies“ zu bezeichnen. Jedoch arbeiten viele Firmen, im besonderen große Firmen, mit dem Produkt.

Die Datensicherheit ist eben ein Argument, welches Unschlagbar erscheint. Die Geschwindigkeit wird sich erst ab ca. 200 Usern zu Gunsten des SQL-Servers verbessern, da dann solch ein Netzwerkverkehr den Fuchs ausbremsen wird.

Microsoft wird mich jetzt warscheinlich erschiessen, aber solange Sie nicht auf SQL-Server entwickeln müssen, bleiben Sie bei VFP, denn hier geht es einfacher, schneller und leichter seine Daten zu verwalten.

Ich habe hier in diesem Schriftstück vieles nicht gesondert angesprochen. Aber Sie haben nun den Grundstock und die wichtigsten Tools um Daten mit dem SQL-Server verwalten zu können.

PS: Das hätt ich beinahe vergessen. Es hat mich eine halbe Glatze gekostet, als ich bemerkte, daß ein SQL-Server Probleme mit Binärdaten hat. Auf den SQL-Server überträgt man Zeichenketten und ein Hexadezimal 0 hat die unangenehme Eigenschaft eine Zeichenkette unter C zu unterbrechen. Denken Sie daran.