Aus Linux-Magazin 05/2013

Der Weg zu Unicode am Beispiel von Datenbanken

© Fotograf, 123RF.com

Moderne Linux-Distributionen benutzen in Zeiten der Globalisierung Unicode, meist in der Ausprägung UTF-8. Vor dieser Ära entstandene ISO-Textdateien lassen sich noch relativ einfach konvertieren. Eine ganze Datenbank ins Heute zu bringen, erfordert Fingerspitzengefühl.

Ob die große Verbreitung von Unicode auf Linux- und anderen Systemen Fluch oder Segen ist, darf dahingestellt bleiben – die Realität ist nun mal wie sie ist. Für den Admin heißt es, seine Daten den Gegebenheiten anzupassen. Glück hat, wer das Stück für Stück tun kann. Für alle anderen bedeutet eine Migration Stress, wenn sie beim Umzug von einem alten Produktivsystem auf ein neues unvermittelt feststellen, dass beispielsweise Umlaute kaputt sind.

Datei-Inhalte konvertieren

Das Problem: Beim Weiterarbeiten schreibt das neue System frisch erzeugte und geänderte Daten mit UTF-8. Nach kurzer Zeit sammelt sich so ein Mischmasch aus Latin und Unicode an, welchen automatisch zu reparieren unmöglich erscheint. Wer in eine solche Zwickmühle gerät, sollte erwägen, schnell auf das alte System zurückzukehren und einen Versuch erst wieder zu wagen, wenn er einen Migrationsplan ausgearbeitet hat. Zur Einstimmung ein paar Fingerübungen: Relevant für die Zeichenkodierung in Linux ist die Variable »LC_CTYPE« ., fuer ISO-8859-15-Systeme etwa:

LANG=de_AT@euro
LC_CTYPE="de_AT@euro"

Auf einem UTF-8-System hingegen materialisiert sich etwas wie

LANG=de_AT.utf8
LC_CTYPE="de_AT@utf8"

Der erste Teil des Wertes »de« gibt die Sprache an und verwendet Codes, die der ISO-639-1-Standard festlegt [1]. Der folgende Abschnitt gibt nach ISO-3166-1 das Land an, im Beispiel »AT« für Österreich [2].

Der dritte Teil definiert die Zeichenkodierung, hier »@euro« für die europäische Erweiterung von ISO-8859-15 oder »@utf8« für die häufigste Kodierung von Unicode ([3],[4]). Die Kodierung nach UTF-8 sorgt dafür, ein Unicode-Zeichen in einer Folge von 1 bis zu 4 Bytes abzubilden (Abbildung 1). Andere Kodierungen bilden die Zeichen aus Unicode in einer anderen Weise ab, beispielsweise UTF-16 immer in Paaren von 2 Bytes.

Abbildung 1: Durch die Kodierungsregeln von UTF-8 sind bestimmte Bytes nicht zulässig. Die Tabelle fasst die 256 Möglichkeiten zusammen. Bytes in roten Zeilen sind unzulässig, grün beschreibt zulässige Bytes, welche unmittelbar ein Zeichen darstellen. In blau sind jene Werte hinterlegt, die eine Sequenz von 2 oder mehr Byte starten und sich als Sequenz mit den Bytes aus orange hinterlegten Zeilen fortsetzen. (Quelle: Wikipedia)

Abbildung 1: Durch die Kodierungsregeln von UTF-8 sind bestimmte Bytes nicht zulässig. Die Tabelle fasst die 256 Möglichkeiten zusammen. Bytes in roten Zeilen sind unzulässig, grün beschreibt zulässige Bytes, welche unmittelbar ein Zeichen darstellen. In blau sind jene Werte hinterlegt, die eine Sequenz von 2 oder mehr Byte starten und sich als Sequenz mit den Bytes aus orange hinterlegten Zeilen fortsetzen. (Quelle: Wikipedia)

Um die Korrektheit der Dateinamen kümmern sich aktuelle Linux-Distributionen normalerweise selbst. Wer beispielsweise von einem externen Datenträger oder übers Netz Dateien, die aus einem Latin8-basierten Betriebssystem stammen, ins neue System kopiert, braucht nichts weiter tun. Bei den Datei-Inhalten trifft das jedoch nicht zu.

Mit dem »file« -Kommando kann sich jeder Anwender eine Liste von Kandidaten zusammenstellen (siehe Listing 1), die er umzuwandeln hat. Es empfiehlt sich, mit einem Texteditor zu überprüfen, ob alle vorgeschlagenen Kandidaten zu Recht auf der Liste stehen. Auch hier bietet sich zur Sicherheit ein Backup an. Die Kommandos »iconv« und »recode« können Dateien zwischen vielen gängigen Kodierungen hin und her konvertieren. Eine Liste der verfügbaren Kodierungen zeigen »iconv -l« und »recode -l« an. Im folgenden Beispiel, das auf die mit Listing 1 erkundeten Daten zurückgreift, bezeichnet »latin9« die ISO-Kodierung inklusive Euro-Zeichen, »utf8« ist die Schreibweise für die Zielkodierung:

xargs -l1 recode latin9..utf8 < kandidaten

Wer mutig ist, lässt durch diesen Aufruf alle Kandidaten zugleich umwandeln.

Listing 1

Ascii-Dateien suchen

01 #!/bin/sh
02
03 if [ -z $1 ]
04 then
05     startdir=$HOME
06 else
07     startdir=$1
08 fi
09
10 find . -exec file {} ; | grep 'ISO-8859 text$' | sed 's/: ISO-8859 text$//' > kandidaten

Datenbank-Applikation umschreiben

Die Inhalte der vermutlich meisten im deutschsprachigen Raum betriebenen Datenbanken liegen in ISO 8859-15 kodiert vor. Ob man eigene auf Unicode umstellt, hängt ganz sicher von der Middleware und/oder der Applikation ab, welche auf die Datenbank zugreifen. Neue Datengräber, so viel lässt sich pauschal empfehlen, sollte man im Sinne der Zukunftssicherheit gleich unicodiert anlegen.

Den größten Teil des Umstellungsprojektes nimmt sicher die Applikation ein. Der Programmierer muss einkalkulieren, dass er die Quellen Zeile für Zeile durchgeht, um nach unmittelbaren und mittelbaren Datenbankoperationen Ausschau zu halten. Die hat er zu untersuchen und gegebenenfalls zu ändern, wenn Variablengrößen für Unicode nicht mehr ausreichen, API-Funktionen ungeeignete Parameter oder Rückgabewerte aufweisen, Checks auf Werte oder Vergleichsoperationen auf zu kleine Ranges lauten oder zu simpel arbeiten und so weiter.

Gerne übersehen werden nach dem Alphabet sortierte Listen: Hier ist nicht nur der viel größere Umfang zu erwartender Buchstaben zu beachten, sondern die Sortierreihenfolge selbst, beispielsweise an welcher Stelle Umlaute und Buchstaben mit Akzenten auftauchen sollen.

Aus der Komplexität ergibt sich fast zwingend die Notwendigkeit, die Applikation im stillen Programmierstübchen abseits des Produktivbetriebs umzubauen. Dazu legt sich der Entwickler eine Testdatenbank gleicher Struktur wie die produktive an, achtet dabei aber darauf, dass sie von Anfang an mit Unicode arbeitet. Dann klont er den Entwicklungszweig für die vorhandene DB-Applikation, biegt sie auf die Testdatenbank um und schreibt sie Stück für Stück auf Unicode um. Erst, wenn das geschafft ist, gehts ans Konvertieren der Produktivdatenbank und Freischalten der neuen Applikation.

Nicht automatisch: MySQL und Unicode

Seit Version 5.0 kennt MySQL zwei Arten Unicode: »ucs2« (UCS-2) und »utf8« (UTF-8), wobei letztere die verbreitetere Kodierung ist. Ohne weitere Angaben starten die meisten MySQL-Installationen aber mit Latin1, also ISO 8859-1. Einen Überblick über die eigenen Gegebenheiten verschafft das Statement »SHOW CHARACTER SET« .

Der Admin darf dem Daemon schon beim Start ein neues Standard-Encoding mitgeben: »mysqld –default-character-set=utf8« . Mit der Option »–default-collation=utf8_general_ci« kann er zugleich die Sortierung bestimmen. Die vorhandene Kollation zeigt »SHOW COLLATION LIKE ‘Suchbegriff‘« . Die nun angezeigte Liste sagt aber nur bedingt etwas über die konkret zu erwartende Sortierung von Umlauten und so weiter aus. Die macht man sich besser am lebenden Objekt mit ein paar Beispieldatensätzen und Abfragen der Art: »SELECT * FROM Tabelle ORDER BY Feldname« klar. Hier geht es etwa darum, ob sich “Ü” bei “U” oder “UE” oder “Ue” oder noch an anderer Stelle einsortiert.

Weiterhin und abweichend von der Datenbank-Engine lässt sich eine einzelne Datenbank beim Anlegen spezifizieren: »CREATE DATABASE DB-Name CHARACTER SET Zeichensatz COLLATE Kollationsname« . Analog geht das sogar auf Tabellenebene: »CREATE TABLE Tabelle (Spaltenliste) DEFAULT CHARACTER SET Zeichensatz […]« und auf Spaltenebene: »Spaltenname VARCHAR (Spaltenlänge) CHARACTER SET Zeichensatz […]« .

Datenbank konvertieren

Gängige Datenbanken lassen sich nicht einfach per Statement als Ganzes oder tabellenweise umkodieren. Das Fehlen einer solchen Funktion ergibt sich vermutlich aus dem relationalen Datenbankmodell mit seinen Entitäten. Ein Konvertierungslauf würde unter Umständen die gespeicherten Schlüsselinformationen korrumpieren, von erweiterten Datenbankfunktionen ganz zu schweigen.

Alles muss raus

Die meisten funktionierenden Anleitungen im Netz [5] entscheiden sich für einen Umweg, der bei genauerer Betrachtung ganz pfiffig ist: Sie schreiben zuerst einen Dump der Datenbank heraus, konvertieren diese Datei, wenn nötig, und lesen den Dump als neue Datenbank wieder ein. Logischerweise ergibt sich daraus eine Nebenbedingung – man braucht temporär reichlich freien Speicher.

Datenbankdumps sind Klartextdateien – wenn nicht anders gewünscht –, die eigentlich fürs Backup oder das Umwandeln von Testdatenbanken in produktive gedacht sind. Dumps enthalten die Daten einer Datenbank und bilden zugleich deren Struktur ab [6]. Bei MySQL schreibt Mysqldump solche Dateien, im konkreten Fall auf folgende Weise:

mysqldump --opt -Q -u DB-User -p Passwort -h localhostDB-Name | sed s'/DEFAULTCHARSET=.*;/DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;/g' > mysql_dump.sql

DB-User, Passwort und DB-Name sind Platzhalter, die der Admin gegen seine eigenen Angaben austauscht. Die Befehlszeile ändert zugleich alle Definitionen von Latin1 auf UTF-8. Anschließend schaut man sich den Typ der entstandenen Datei an:

file -i mysql_dump.sql

Falls es nicht »utf-8 text« , sondern das wahrscheinlichere »ISO-8859 text« ist, konvertiert man einfach die Datei manuell, beispielsweise über:

iconv -f Zeichensatz -t utf8 mysql_dump.sql > mysql_dump.utf8.sql

Die »Zeichensatz« -Angabe ist dann vom Admin anhand der ihm vorliegenden Datei zu konkretisieren.

Zurück in die Zukunft

Dann bestückt der Admin die künftige Produktivdatenbank und benutzt dabei die Option »default-character-set=utf8« :

mysql -u DB-User -p Passwort -h localhost--default-character-set=utf8DB-Name < mysql_dump.utf8.sql

Nun sollte die neue Datenbank durchgängig in UTF-8 kodiert sein, was sich mit gängigen Abfragetools prüfen lässt. PHP Myadmin müsste als Tabellen-Kollation »utf8_unicode_ci« melden. Ebenfalls in PHP Myadmin sollte der Admin unter »Operationen« noch die Standard-Kollation auf »utf8_unicode_ci« stellen.

Ganz ähnlich wie in MySQL läuft die Sache für Oracle-Datenbanken, nur dass die Engine beim Einlesen selbst die Konvertierung vornimmt (siehe Kasten “Oracle-Datenbank konvertieren”).

Oracle-Datenbank konvertieren

Ähnlich wie bei MySQL läuft auch das Konvertieren einer Oracle-Datenbank. Das erste Ziel ist, ein so genanntes logisches Backup anzufertigen. Ab Oracle 11g passiert das mit dem Tool Data Pump ([7], Kommando »expdp Benutzer/Passwort Kommando-Optionen« ). Bei älteren Versionen kommt das Kommando »exp« zu Ehren, das eine ähnliche Syntax aufweist – insbesondere, wenn man Data Pump im Legacy-Modus gewöhnt ist. Kommandos lassen sich sehr, sehr umfangreich ausgestalten, beispielsweise um nur bestimmte Teile der Datenbank zu exportieren.

Ist das geschafft, legt der Admin eine neue Datenbank mit UTF-8 an. Beim Zurückspielen des erzeugten Backups mit »impdp« beziehungsweise »imp« in die neue Datenbank konvertiert die Datenbank-Engine selbstständig die enthaltenen Zeichen. Wichtig ist, dass die Variable »NSL_LANG« beim Backup und beim Restore auf dem zum Inhalt passenden Wert steht – beim vorliegenden Vorhaben ist das regelmäßig der gleiche! Das Statement

SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER='NLS_CHARACTERSET';

ermittelt jedoch zu Beginn erstmal, in welchem Zeichensatz Oracle meint die Datenbank gespeichert zu haben.

Was bei der Migration zu welchem Zeitpunkt zu sichern und zurückzuspielen ist, hängt von der Struktur der Datenbank und der Erwartung der zugehörigen Applikation beziehungsweise Middleware ab.

Infos

  1. Abkürzungen für Sprachen nach ISO 639: http://de.wikipedia.org/wiki/ISO_639
  2. Abkürzungen für Länder nach ISO 3166: http://de.wikipedia.org/wiki/ISO_3166
  3. Bruno Haible, Oliver Frommel, “In fremden Zungen”: Linux-Magazin 10/04, S. 118
  4. Kester Habermann, Nils Magnus, “Abschrift”: Linux-Magazin 01/08, S. 76
  5. “MySQL Datenbank in UTF-8 konvertieren”: http://ppfeufer.de/mysql-datenbank-in-utf-8-konvertieren/
  6. Thomas Wölfer, “MySQL-Datenbanken sichern – Teil 1”: Linux-Magazin 05/04, S. 60
  7. Data Pump Export: http://docs.oracle.com/cd/E11882_01/server.112/e10701/dp_export.htm#SUTIL200
DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 3 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben