Lade...
 

SQL ODBC

SQL ADO/ODBC

Um mit ClassiX auf SQL-Datenbanken zuzugreifen, kann aktuell die ADO-COM-Schnittstelle verwendet werden. Die ADO-COM-Objekte verwenden die standardisierte ODBC-Datenbankschnittstelle. Die meisten großen SQL-Datenbanken stellen für ihre Datenbanken ODBC-Treiber zur Verfügung, die zunächst installiert werden müssen, ehe auf die Datenbank zugegriffen werden kann.

Treiber einrichten

Auf der Maschine, auf der ClassiX laufen soll, muss der zur Datenbank passende ODBC-Treiber (64-Bit) installiert werden. Hierzu muss man zunächst herausfinden, welche Datenbank genau angebunden werden soll und dann findet man auf der Herstellerseite die entsprechenden Treiber.

Hier sind Treiber für einige bekannte Datenbanken:

Nachdem der Treiber installiert wurde, sollte er in den ODBC-Datenquellen (64-Bit)  unter den Treibern aufgeführt sein. Zum Öffnen des Verwaltungsprogramms einfach "ODBC" ins Startmenü eingeben und dort die richtige Version aussuchen.

Odbc Drivers

DSN einrichten

Windows nutzt für ODBC das Konzept von DSNs (Data Source Name), um über einen Bezeichner von der konkreten Datenbank zu abstrahieren. Es ist nicht notwendig, einen DSN einzurichten, jedoch erleichtert er die Anbindung und den Austausch von Datenbanken ungemein. Wird kein DSN eingerichtet, dann müssen im Connection-String bei jeder Verbindung der Treiber, User, Datenbank & Password angegeben werden.

Für die Einrichtung eines DSNs geht man im ODBC-Datenquellen-Administrator auf den Tab Benutzer-DSN und klickt auf Hinzufügen und wählt im nächsten Fenster den installierten ODBC-Treiber aus.

Dsn 1

Anschließend wird nach dem Namen gefragt. Dieser Name wird später im Connection-String hinter DSN= angegeben, oder falls der DSN alle notwendigen Verbindungsinformationen enthält, dann reicht später die Angabe dieses Namens als Connection-String.

Dsn 2

Anschließend wird je nach Datenbankart nach den Verbindungsdaten oder der Datei gefragt. Hier kann auch direkt der Nutzer und die Datenbank angegeben werden, sodass diese Information nicht im Connection-String stehen muss. Bei MySQL ist der Standardnutzer "root" ohne Passwort.

Per Test DSN lässt sich hier eine Verbindung zur Datenbank herstellen und dann kann auch eine der dort vorhandenen Datenbanken ausgewählt werden.

In den bisherigen Tests mit MySQL musste zunächst die Verbindung zur Datenbank per Test DSN aufgebaut werden und dann aus dem dann befüllten Dropdown die Datenbank ausgewählt werden. Wurde ohne Test DSN lediglich der Datenbankname eingetragen, dann wurde später bei der Verwendung der Fehler gemeldet, dass keine Datenbank im Connection-String gesetzt wurde.

Dsn 3

Anschließend können noch ein paar Optionen gesetzt werden.

Dsn 4

Dsn 5

Dsn 6

Dsn 7

Nun sollte der neue DSN in der Liste der Benutzer-DSNs aufgeführt sein.

Verbindung aufbauen

Mit DSN

Mit dem DSN aus dem vorherigen Schritt lässt sich eine Verbindung einfach wie folgt aufbauen.

Var(connection) 
CreateTransObject(CX_COM_OBJECT) -> connection
"ADODB.Connection" connection Call(CreateFromProgID)
"MySQL-Test" connection Call(Open)

Falls die Angaben im DSN nicht ausreichen, dann können weitere Angaben im Connection-String durchgeführt werden, wenn 

"DSN=MySQL-Test;UserID=root;DB=test" connection Call(Open)

Ohne DSN

Wurde kein DSN definiert, dann müssen die dort getätigten Angaben im Connection-String erfolgen. Dies ist recht Fehleranfällig und aufgrund der Treiberspezifischen Optionen nicht empfehlenswert. Das obige Beispiel ohne DSN würde wie folgt ausshen:

Var(connection) 
CreateTransObject(CX_COM_OBJECT) -> connection
"ADODB.Connection" connection Call(CreateFromProgID)
"Driver={MariaDB ODBC 3.0 Driver};server=localhost;DB=test;Uid=root" connection Call(Open)

Werte, die Leerzeichen enthalten müssen in geschweiften Klammern eingeschlossen sein.

 

Connection-Strings

Die bei ADODB.Connection.Open angegebenen Connection-Strings können entweder der Name eines DSNs sein, oder eine Liste von Schlüssel-Wert-Paaren. Dabei sind die Schlüssel Case-Insensitiv und Leerzeichen-Insensitiv. Eine Liste der standardisierten Schlüssel und ihrer Kurzformen findet sich hier.

Einige Treiber definieren ihre eigenen Schlüssel. Der Schlüssel DB aus dem obigen Beispiel wird beispielsweise für MySQL benötigt, um die Datenbank anzugeben, ist jedoch in dem verlinkten Dokument nicht dokumentiert. Häufig muss man das Internet nach Connection-String-Beispielen für die korrekte Syntax durchsuchen. Die Seite https://www.connectionstrings.com/ enthält auch eine Reihe an Beispiel-Connection-Strings die als Ausgangspunkt dienen können.

 

SQL-Query ausführen

Um einen SQL-Befehl abzusetzen, kann man entweder ein ADODB.command-Objekt verwendet werden, oder alternativ die Query direkt auf einem ADODB.recordset (einfacher) ausführen. 

Beispiel - Direkt auf einem Recordset

Var(records)
CreateTransObject(CX_COM_OBJECT) -> records
"ADODB.recordset" records Call(CreateFromProgID)

"SELECT * FROM `items`" connection records Call(Open)

// Alternatively with Paging
// "SELECT * FROM `items` LIMIT 10 OFFSET 10" connection records Call(Open)

Beispiel - Mit Command-Objekt

Var(command, records)
CreateTransObject(CX_COM_OBJECT) -> command
"ADODB.command" command Call(CreateFromProgID)

connection command Call(PutActiveConnection)
"SELECT * FROM `items`" command Call(PutCommandText)

command Call(Execute) -> records

 

Ergebnis auswerten

Die Ergebnisse der Query liegen in dem RecordSet vor. Das RecordSet hat die Eigenschaft RecordCount (Call(GetRecordCount)), welche die Anzahl der enthaltenen Zeilen enthält. Dies kann zum Beispiel verwendet werden, dem Nutzer einen Fortschrittsbalken bei der Verarbeitung von vielen Daten zu anzuzeigen.

Achtung: Der Treiber definiert den Funktions-/Informationsumfang der zurückgegebenen COM-Objekte. Der bei den Tests verwendete MySQL-Treiber hat beispielsweise immer einen RecordCount von -1 geliefert und hat Felder vom Typ DECIMAL als 0 übertragen.
Der RecordCount lässt sich alternativ auch über eine zusätzliche Query ermittelt werden, die vorher ausgeführt wird.
SELECT COUNT(*) FROM ... WHERE ... 
Das Ergebnis dieser Query enthält immer genau eine Zeile mit einer Spalte, die die Anzahl der Zeilen enthält.

Über GetFields erhält man eine Collection von Spalten der aktuellen Zeile des Recordsets. Jede Spalte ist vom Typ ADODB.field.

Ein Recordsset hält einen Cursor, der die aktuelle Zeile kennt. Per MoveNext kann der Cursor zur nächsten Zeile weitergeschaltet werden und per GetEOF kann geprüft werden, ob die aktuelle Zeile noch gültig ist.

Beispiel - Umwandlung eines Recordsets in einen Vector von JSON-Objekten

Var(numberOfRecords, numberOfColumns, recordVector)
records Call(GetBOF) records Call(GetEOF) & if {
  // Empty recordset
  [ ] # return
}


records Call(MoveFirst)
records Call(GetRecordCount) -> numberOfRecords
records Call(GetFields) Call(GetCount) -> numberOfColumns
// Preallocate vector size if RecordCount is supported
numberOfRecords 0 > if { CreateVector(STACK) } else { [] } -> recordVector
do
  CreateTransObject(CX_JSON_OBJECT) Dup -> jsonObject recordVector Insert
  LocalVar(column, fieldsColl)
  0 -> column
  records Call(GetFields) -> fieldsColl
  do
    LocalVar(itemObject, itemName, itemValue)
    column fieldsColl Call(GetItem) -> itemObject
    itemObject Call(GetName) -> itemName
    itemObject Call(GetValue) -> itemValue
    itemValue jsonObject itemName Put(STACK)
    Incr(column)
    column numberOfColumns <
  while
  DropAll
  records Call(MoveNext)
  records Call(GetEOF) !
while

InstantView®