Die ODBC-Lösung
Die Frage lautet dann: Wie standardisiert ODBC den Datenbankzugriff? Es gibt zwei Anforderungen an die Architektur:
Anwendungen müssen ohne erneute Kompilierung oder Verknüpfung mit demselben Quellcode auf mehrere DBMS zugreifen können.
Anwendungen müssen auf mehrere DBMSs gleichzeitig zugreifen können.
Und es stellt sich noch eine weitere Frage, die sich aus der Realität des Marktes ergibt:
- Welche DBMS-Features sollte ODBC verfügbar machen? Nur Features, die alle DBMSs gemeinsam haben, oder alle in jedem DBMS verfügbaren Features?
ODBC löst diese Probleme auf folgende Weise:
ODBC ist ein Call-Level-Interface. Zum Lösen des Problems, wie Anwendungen mit demselben Quellcode auf mehrere DBMS zugreifen sollen, definiert ODBC eine Standard-CLI. Sie enthält alle Funktionen aus den CLI-Spezifikationen von Open Group und ISO/IEC sowie zusätzliche Funktionen, die von Anwendungen oft gebraucht werden.
Für jedes DBMS, das ODBC unterstützt, ist eine andere Bibliothek oder ein anderer Treiber erforderlich. Der Treiber implementiert die Funktionen in der ODBC-API. Zum Verwenden eines anderen Treibers muss die Anwendung nicht erneut kompiliert oder verknüpft werden. Stattdessen lädt die Anwendung einfach den neuen Treiber und ruft die darin enthaltenen Funktionen auf. Für den gleichzeitigen Zugriff auf mehrere DBMSslädt die Anwendung mehrere Treiber. Die Art der Unterstützung von Treibern ist betriebssystemspezifisch. Auf dem Microsoft Windows-Betriebssystem handelt es sich bei den Treibern z. B. um Dynamic Link Libraries (DLLs).
ODBC definiert eine SQL-Standardgrammatik. Zusätzlich zu einem standardmäßigen Call-Level-Interface definiert ODBC eine SQL-Standardgrammatik. Diese Grammatik basiert auf der SQL-CAE-Spezifikation der Open Group. Die Unterschiede zwischen den beiden Grammatiken sind geringfügig und in erster Linie auf die Unterschiede zwischen der SQL-Grammatik für eingebettetes SQL (Open Group) und eine CLI (ODBC) zurückzuführen. Es gibt auch einige Erweiterungen der Grammatik, um gängige Sprachfeatures verfügbar zu machen, die von der Open Group-Grammatik nicht abgedeckt werden.
Anwendungen können Anweisungen nach der ODBC- oder DBMS-spezifischen Grammatik übermitteln. Wenn eine Anweisung die ODBC-Grammatik verwendet, die sich von der DBMS-spezifischen Grammatik unterscheidet, wird sie vom Treiber konvertiert, bevor sie an die Datenquelle gesendet wird. Solche Konvertierungen sind jedoch selten, da die meisten DBMSs bereits die SQL-Standardgrammatik verwenden.
ODBC verfügt über einen Treiber-Manager zum Verwalten des gleichzeitigen Zugriffs auf mehrere DBMSs. Der Einsatz von Treibern löst zwar das Problem des gleichzeitigen Zugriffs auf mehrere DBMSs, aber der dafür erforderliche Code kann komplex sein. Anwendungen, die auf das Zusammenwirken mit allen Treibern ausgelegt sind, können nicht statisch mit Treibern verknüpft werden. Stattdessen müssen sie Treiber zur Laufzeit laden und die darin enthaltenen Funktionen über eine Tabelle mit Funktionszeigern aufrufen. Noch komplexer wird die Situation, wenn die Anwendung mehrere Treiber gleichzeitig verwendet.
ODBC verfügt über einen Treiber-Manager, der den einzelnen Anwendungen diese Arbeit abnimmt. Der Treiber-Manager implementiert alle ODBC-Funktionen – in erster Linie als Passthrough-Aufrufe von ODBC-Funktionen in Treibern – und ist statisch mit der Anwendung verknüpft oder wird zur Laufzeit von der Anwendung geladen. Daher ruft die Anwendung ODBC-Funktionen anhand des Namens im Treiber-Manager und nicht anhand des Zeigers in jedem Treiber auf.
Wenn eine Anwendung einen bestimmten Treiber braucht, fordert sie zuerst einen Verbindungshandle zum Bezeichnen des Treibers an und fordert dann den Treiber-Manager zum Laden des Treibers auf. Der Treiber-Manager lädt den Treiber und speichert die Adresse jeder Funktion im Treiber. Zum Aufrufen einer ODBC-Funktion im Treiber ruft die Anwendung diese Funktion im Treiber-Manager auf und übergibt den Verbindungshandle für den Treiber. Der Treiber-Manager ruft dann anhand der zuvor gespeicherten Adresse die Funktion auf.
ODBC macht eine erhebliche Anzahl von DBMS-Features verfügbar, die von den Treibern aber nicht alle unterstützt werden müssen. Es wäre nicht sehr sinnvoll, wenn ODBC nur die Features verfügbar machen würde, die alle DBMSs miteinander gemeinsam haben. Schließlich gibt es heute deshalb so viele verschiedene DBMSs, weil sie unterschiedliche Features haben. Wenn ODBC alle in jedem DBMS vorhandenen Feature verfügbar machen würde, wäre die Implementierung für Treiber unmöglich.
Stattdessen macht ODBC eine erhebliche Anzahl von Features verfügbar – mehr als von den meisten DBMSs unterstützt –, verlangt aber von den Treibern nur die Implementierung einer Teilmenge dieser Features. Die übrigen Features werden von Treibern nur dann implementiert, wenn sie vom zugrunde liegenden DBMS unterstützt werden oder wenn sie emuliert werden sollen. Daher können Anwendungen so geschrieben werden, dass sie die Features eines einzelnen DBMS so nutzen, wie sie vom Treiber für dieses DBMS verfügbar gemacht werden, dass sie nur die von allen DBMSs verwendeten Features nutzen oder dass sie prüfen, ob ein bestimmtes Feature unterstützt wird, und entsprechend reagieren.
Damit eine Anwendung bestimmen kann, welche Features von einem Treiber und einem DBMS unterstützt werden, verfügt ODBC über zwei Funktionen (SQLGetInfo und SQLGetFunctions), die allgemeine Informationen über die Treiber- und DBMS-Funktionen und eine Liste der vom Treiber unterstützten Funktionen zurückgeben. ODBC definiert auch API- und SQL-Grammatik-Konformitätsgrade mit einer breiten Palette von Features, die vom Treiber unterstützt werden. Weitere Informationen finden Sie unter Konformitätsgrade.
Es darf nicht vergessen werden, dass ODBC eine gemeinsame Schnittstelle für alle verfügbaren Features definiert. Aufgrund dessen enthalten Anwendungen einen Feature-spezifischen Code und keinen DBMS-spezifischen Code und können alle Treiber nutzen, die diese Features verfügbar machen. Das hat den Vorteil, dass Anwendungen nicht aktualisiert werden müssen, wenn die von einem DBMS unterstützten Features erweitert werden. Beim Installieren eines aktualisierten Treibers werden die Features stattdessen von der Anwendung automatisch verwendet, weil ihr Code Feature-spezifisch ist und nicht Treiber- oder DBMS-spezifisch.