Gestern und heute habe ich einige Stunden damit verbracht nach einem Fehler zu suchen, der erst auftrat, als eine bei einer Rails Anwendung die Datenbank von MySQL auf SQL Server gändert wurde.
Beim Auslesen eines Passwordhashs aus einem Zeichenfeld wurde von Rails statt dem letzten Zeichen ein Null Charakter zurückgegeben. Dies geschah nur, wenn die Länge des Strings der Länge der Spalte entstprach, hier waren es 40 Zeichen. Vergrößerte man die Spalte auf 41 kam der richtige Wert zurück.
Es konnte schnell ausgeschlossen werden, daß es an der Datenbank, oder an der ODBC Einstellung lag, da mit anderen Anwendungen der richtige Inhalt zurückkam. Die Ursache lag also zwischen der Anwendung und der ODBC Verbindung. Dies gab mir die Gelegenheit die Komponenten dazwischen und ruby-debug genauer kennenzulernen, also den activerecord-sqlserver adapter, ruby-dbi und ruby-odbc. Leider konnte ich nichts finden, da der Debugger trotz Step into nicht in eine Funktion hineinspang. Nach einer Weile wusste ich auch warum. Ich lud mir den Quellcode zu ruby-odbc herunter und erkannte, daß es eine Funktion einer Binärlibrary war. Die auch noch zu debuggen war mir zu viel, es war auch schon kurz vor Feierabend. Ich schrieb dem Autor von ruby-odbc, da ich annahm, daß das Phänomen möglicherweise schon bekannt ist.
Da mir der Autor abends schon antwortete konnte ich am nächsten Tag gleich sinnvoll weitermachen. Er schlug vor die ODBC Daten zu protokollieren. Das Tracen klappte nicht sofort, weil komischerweise nur die SQLs von Migrationen getraced wurden, nicht die SQLs der Anwendung, aber das Log brachte mich der Lösug schon viel näher. Dort sah ich das die von ruby verwendete Feldlänge nur die Hälfte der Länge der Abfrage von MS Access war. ruby-odbc sah also nicht, daß dies ein Unicode Feld war.
Ich sah mir dann den Code der odbc Bibliothek an und mir fielen #ifdef unicode Zeilen auf, woraus ich schloß, das Unicode eine Konfigurationsmöglichkeit sein muß. Daraufhin tat ich das, was man eigentlich als erstes machen sollte. Ich las die README Datei in der tatsächlich die Lösung stand:
if $KCODE == "UTF8" then require 'odbc_utf8' else require 'odbc' end
Dies fügte ich in dbd/odbc.rb was auch in diesem Patch zu finden ist.