Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Lesen/Schreiben von BINARY(16) über DataSet (https://www.delphipraxis.net/217418-lesen-schreiben-von-binary-16-ueber-dataset.html)

tumo 25. Jun 2025 22:03

Datenbank: MySQL • Version: 9 • Zugriff über: FireDAC

Lesen/Schreiben von BINARY(16) über DataSet
 
Hallo allesamt,

Ich habe eine MySQL-(kompatible)-Datenbank mit folgender Tabelle:
Code:
CREATE TABLE test(
  id BINARY(16) PRIMARY KEY,
  name VARCHAR(255),
  picture BLOB
);
Wie vielleicht zu erwarten, ist die Spalte "id" für eine UUID/GUID gedacht.
Nun möchte ich Daten in diese einfügen. Aufgrund des geerbten Codes, der stark auf der TDataSet-Klasse aufbaut, muss ich dies über besagte TDataSet-Objekte abfertigen. Folgender Code kam mir da in den Sinn
Delphi-Quellcode:
fConnection := TFDConnection.Create(nil);
fConnection.Open('DriverID=MySQL;Host=localhost;Port=3306;Database=test;User_Name=root');

var Q := TFDQuery.Create(nil);
Q.Connection := fConnection;
Q.Open('SELECT * FROM test LIMIT 0'); // DataSet für Tabelle "test" holen

Q.Append;
Q.FieldByName('id').AsBytes := fGUID.ToByteArray;
Q.FieldByName('name').AsString := fName;

var S := Q.CreateBlobStream(Q.FieldByName('picture'), bmWrite);
try
  S.Size := 0;
  fPngPicture.Position := 0;
  S.CopyFrom(fPngPicture);
finally
  S.Free;
end;
Q.Post;
So wie es da steht, bekomme ich den Fehler, dass das Feld "id" nur Strings der Länge 5 akzeptiert, der gegebene String aber die Länge 6 hat:
[FireDAC][DatS]-32. Überlauf der Spalte[id] mit variabler Länge. Wertlänge - [6], Maximallänge der Spalte - [5]
Ein Blick auf die Datentypen verrät, dass er die Spalte "id" als ftFixedWideChar interpretiert. ftBytes erscheint mir passender.

Definiert man in der Connection noch "CharacterSet=Binary", wird die Spalte als ftFixedChar anerkannt, der Fehler kommt weiterhin, nur mit den Zahlen 16 und 17. Umgeht man diesen Fehler durch Kürzen des Arrays, findet man aber ein viel größeres Problem: "fName" wird nicht in UTF8 konvertiert. Jedenfalls beschwert er sich, dass es sich um keine gültige utf8mb4-Sequenz handelt.

Andererseits kann man auch "CharacterSet=utf8mb4" definieren, ändert nur nix an der Problematik ohne den Parameter.

Nun zur Frage: Wie arbeite ich korrekt mit einem Datenbank-Feld vom Type BINARY/VARBINARY? Entweder er konvertiert mir die Feldgröße weg (16 -> 5) oder er hängt (scheinbar) einen Null-Character an meine Daten und beschwert sich dann, dass die zu lang sind.

Ein weiteres Problem, was ich jetzt nicht mehr nachstellen kann ist, dass er beim definieren von "CharacterSet=utf8mb4" auch den PNG-Stream "konvertiert" hat. Da kam ganz schön viel chinesisch raus.

Zwei Tage googlen haben keine Früchte getragen, scheinbar hat niemand sonst das Problem :(

himitsu 26. Jun 2025 00:15

AW: Lesen/Schreiben von BINARY(16) über DataSet
 
[EDIT]
Es ist alles Richtig. DU hast gesagt du willst einen STRING, also hat die DB dir auch einen STRING gegeben.
Zitat:

Zitat von BINARY
Zum Speichern binärer Strings, unabhängig vom Zeichensatz. Wertebereich für M: 0 bis 255. Weiterer Typ: VARBINARY

https://www.schmager.de/mysql.php

Du wolltest bestimmt den Typ "BLOB", bzw. BLOB(16) verwenden? :zwinker:
(einige andere DBMS bieten sogar direkt einen Typen für GUID, inkl. einer automatischen VARCHAR-Konvertierung, falls man sowas braucht)

Aber ja, ich hätte unter "BINARY" auch erstmal was Anderes verstanden :duck:
[/EDIT]


DBTypen, welche die Query-Komponente nicht versteht, bzw. nicht implementiert hat, weichen als Ersatz gern auf VARCHAR aus.

Und da UTF-8 in DBMS nunmal statisch 3 (bis 5) Byte pro Char reserviert, passen in 16 Byte zufällig nur 5 Chars rein. :angle:
  • entweder du nutzt eine andere DBKomponente, welche z.B. genau auf das gewünschte DBMS ausgelegt ist
  • oder du erstellst selber die TField (TBlobField) und richtest sie passend ein (BlobType=ftBlob)
    (Dank dem neuen MixedMode muß man nun auch nicht mehr ALLE Felder selbst erstellen, sondern nur noch die Nötigen)
  • oder du spielst am TypeMapping rum, wo du selbst ensprechend die DBTypen zum gewüünschten TField-Typ definierst
  • oder ...


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

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