Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird Character Set ändern (https://www.delphipraxis.net/176647-firebird-character-set-aendern.html)

christophspaeth 18. Sep 2013 15:46

Datenbank: Firebird • Version: 2.5 • Zugriff über: UIB

Firebird Character Set ändern
 
Hallo zusammen,

Beim Portieren eines älteren Datenbankprojektes von Delphi 2006 auf XE2, also Unicode, bin ich auf ein Problem mit meiner Datenbank gestoßen.

In der DB ist soweit ich das überblicke kein Character set oder collation hinterlegt; die Daten sind aber als UTF8 hinterlegt (hier muss ich noch überprüfen, ob das wirklich für alle chars und varchars gilt)
Bisher wurde mittels AnsiToUtf8() UTF-8 Codiert und direkt in das SQL-Statement eingebettet
Delphi-Quellcode:
query.sql.text := 'update mytable set name= ' + SqlQuoteAndEscape(AnsiToUtf8('Müller')) + ...


Bei der Umstellung auf Unicode wird das vermutlich so nicht mehr funktionieren, außerdem möchte ich in dem Zuge gleich auf prepared statements umstellen.
Das manuell nach UTF8 zu codieren und dann als RawByteString übergeben funktioniert zwar,
Delphi-Quellcode:
query.Params.ByNameAsRawByteString['name'] := UTF8Encode('Müller');

ich frage mich aber, ob es nicht sinnvoller/richtiger wäre, die Charset-Information in der Datenbank zu hinterlegen, dann müsste es ja reichen, einfach den (Unicode)String zuzuweisen:
Delphi-Quellcode:
query.Params.ByNameAsString['name'] := 'Müller';


Hier stehe ich nur vor der Frage, ob das so einfach geht bzw. welche Nebenwirkungen das haben kann.
Laut Firebird-Dokumentation müsste das Umstellen ja mit
Code:
alter character set utf8 set default collation unicode_ci_ai;
möglich sein?
[Edit: Anscheinend wird damit die default Collation für das angegebene charset geändert, und nicht wie von mir angenommen das default charset der DB]

Nachdem ich die collations noch nicht so ganz verstanden habe und es doch diverse Themen zu Konvertierungsproblemen mit nicht unterstützten/vorhandenen collations gibt, frage ich lieber einmal zu häufig.

Also die Fragen nochmal zusammengefasst:
1. Kann ich relativ gefahrlos den Zeichensatz meiner Datenbank ändern?
2. Muss ich dabei auf etwas aufpassen?
3. Gibt es Gründe, warum die DB nichts über den verwendeten Zeichensatz wissen soll und ich das besser so lasse wie es ist?

Danke für's Lesen (und hoffentlich auch Antworten :))

christophspaeth 20. Sep 2013 15:09

AW: Firebird Character Set ändern
 
Ich habe mein Update jetzt durchgeführt. Für den Fall, dass jemand eine ähnliche Problemstellung hat (oder mir sagt, dass irgendwas von dem gemachten ganz gefährlich oder böse ist), beschreibe ich mal, was ich getan habe:

- einen offiziellen Weg, bei einer bestehenden Datenbank das default charset zu ändern habe ich nicht gefunden. Nachdem meiner Recherche zufolge bei Firebird das Client-Charset und Server-Charset zusammenpassen muss, ist das eh reine Metadata. Geändert werden kann das trotzdem in den Systemtabellen mit
Code:
update RDB$DATABASE set RDB$CHARACTER_SET_NAME = 'UTF8';
- bei der UIB muss dann auf der Connection noch das (Client-)Chaset angegeben werden:
Delphi-Quellcode:
// set database, user, password, client dll
DbConection.CharacterSet := csUTF8;
DbConection.Connected := true;
- Natürlich gab es noch Tabellen, die noch ANSI-Daten hatten. Nachdem das nur wenige Tabellen mit wenigen Einträgen waren, lauf ich da einzeln drüber und codiere von Hand um. Hier habe ich noch kein Charset auf der Verbindung geändert. Das Projekt ist auch noch auf Delphi 2006, deswegen auch kein ByNameAsRawByteString.
Delphi-Quellcode:
DBQueryRead.SQL.Text := 'select id, link_name from mytable';
DbQueryWrite.SQL.Text := 'update mytable set link_name=:Name where id=:ID';
// ignore int columns and columns with guaranteed pure ASCII data

DbQueryRead.Open();
while not DbQueryRead.Eof do
begin
    DbQueryWrite.Params.ByNameAsInteger['ID'] := DbQueryRead.Fields.ByNameAsInteger['id'];
    DbQueryWrite.Params.ByNameAsString['Name'] := AnsiToUtf8(DbQueryRead.Fields.ByNameAsString['link_name']);
    DbQueryWrite.Execute();
   
    DbQueryRead.Next();
end;
Grüße
Chris

Delphi.Narium 6. Jan 2018 14:50

AW: Firebird Character Set ändern
 
Auch wenn es schon 'ne Weilte her ist:

Hatte gerade ein ähnliches Problem mit 'ner Firebird 3-Datenbank. Die Lösung war:
SQL-Code:
alter database set default character set UTF8
Statt UTF8 nehmen man ggfls. das, was man benötigt.

Das
SQL-Code:
update RDB$DATABASE set RDB$CHARACTER_SET_NAME = 'UTF8';
wird mit 'nem Fehler quittiert, ein Update auf die Tabelle ist nicht zulässig.

hoika 6. Jan 2018 15:47

AW: Firebird Character Set ändern
 
Hallo,
in FB3 ist ein Schreib-Zugriff auf die Systemtabellen nicht mehr erlaubt.

hstreicher 7. Jan 2018 06:51

AW: Firebird Character Set ändern
 
also ich würde so nicht vorgehen , da die verschiednen Zeichensätze verschiedene Byte Größen haben ändern sich die benötigten Puffergrößen und man kann sich mit der Umstellung von z.b Win1252 1-Byte auf UTF-8 4 Byte die maximalen Größen der Records in Firebird (64 KB) überschreiten,
imho richtig wäre die folgende Vorgehensweise

Metatdaten Exportieren
Charset(s) anpassen
Datenbank neu erstellen
prüfen ob alle Tabellen übernommen wurden , ggf Tabellenstruktur überarbeiten
und dann die Daten von der alten DB in die Neue DB pumpen mit einem Programm das auch die Charset Transformation beherrscht

z.b. https://github.com/zedalaye/fbclone

fbclone
Automatically exported from code.google.com/p/fbclone
FBClone can clone a http://www.firebirdsql.org database in one shot (instead of backup/restore cycle) and pump data from one database to another with the same structure, it handles metadata / data charset conversion and may be useful to ease database owner change process or to migrate a database between two different firebird versions (eg. 2.1 -> 1.5)
Latest version have flags to ignore charset definitions from source database metadata so you can "normalize" a database with multiple charsets to only one, for instance, UTF8 (see -ics and -ko flags in conjunction to -tc UTF8)


hth Hannes

IBExpert 7. Jan 2018 18:37

AW: Firebird Character Set ändern
 
In rdb$database ist nur der Default Charset hinterlegt, der wird bei neuen Tabellenfeldern genommen, wenn
nicht explizit was anderes angegeben wird. Das hat aber keinerlei Einfluß auf bereits existierende Tabellen.

Wir machen das immer so:

1. Datenbank mit geeignetem Tool in ein Script exportieren mit Metadaten, Daten und auch Blobs (geht z.B. in der
IBExpert Vollversion). Charset Angaben nicht exportieren bzw. per suchen/ersetzen löschen.
2. Eine neue UTF8 DB anlegen
3. Das in 1. erzeugte Script mit dem alten Charset (oder bei NONE trotzdem ISO8859_1) an die UTF8 DB
connecten und ausführen. Dabei übernimmt Firebird selber die Konvertierung aller benutzten Sonderzeichen
in geeignete UTF8 Zeichen.
4. Evtl. Limitierungen werden zu Fehlern führen, z.B. char oder varchar deklarationen länger als 8191
Diese falls vorhanden im Script ersetzen und noch mal probieren. der Vorgang kann mit ibec_extract_metadata
in ibexpert auch per script automatisiert werden, wenn man das für mehrere Kunden/DB braucht

madas 2. Feb 2018 06:29

AW: Firebird Character Set ändern
 
Zitat:

Zitat von IBExpert (Beitrag 1390434)
In rdb$database ist nur der Default Charset hinterlegt, der wird bei neuen Tabellenfeldern genommen, wenn
nicht explizit was anderes angegeben wird. Das hat aber keinerlei Einfluß auf bereits existierende Tabellen.

Wir machen das immer so:

1. Datenbank mit geeignetem Tool in ein Script exportieren mit Metadaten, Daten und auch Blobs (geht z.B. in der
IBExpert Vollversion). Charset Angaben nicht exportieren bzw. per suchen/ersetzen löschen.
2. Eine neue UTF8 DB anlegen
3. Das in 1. erzeugte Script mit dem alten Charset (oder bei NONE trotzdem ISO8859_1) an die UTF8 DB
connecten und ausführen. Dabei übernimmt Firebird selber die Konvertierung aller benutzten Sonderzeichen
in geeignete UTF8 Zeichen.
4. Evtl. Limitierungen werden zu Fehlern führen, z.B. char oder varchar deklarationen länger als 8191
Diese falls vorhanden im Script ersetzen und noch mal probieren. der Vorgang kann mit ibec_extract_metadata
in ibexpert auch per script automatisiert werden, wenn man das für mehrere Kunden/DB braucht

Muss solche eine ISO8859_1 DB für die Verwendung in D2009 mit UIB zwingend so konvertiert werden? Oder reicht es wenn man beim Connect das Client CharSet auf "None" setzt bzw. könnten durch das setzen auf "None" irgend welche Probleme auftreten?

madas


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:10 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz