SQLDB und die Größe der Datenfelder (MariaDB/MySQL)

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

SQLDB und die Größe der Datenfelder (MariaDB/MySQL)

Beitrag von Socke »

Hallo zusammen,

SQLDB erstellt mir automatisch ein Feld vom Typ ftFixedChar mit der falschen Länge? Wie kann ich SQLDB dazu überreden, die korrekte Länge automatisch von der Datenbank zu beziehen. Ich habe nicht vor, die Felddefinitionen von Hand anzulegen. Ein Wechsel auf ZEOS ist ebenfalls ausgeschlossen (kann aber gerne als Referenz für eine ggf. korrekte Ermittlung der Feldlänge angegeben werden).
Aktuell gehe ich von einem Fehler in SQLDB aus, da das Programm HeidiSQL die Abfrageergebnisse korrekt darstellt.

Eingesetzt werden:
  • MariaDB Version 10.0.31-MariaDB als Server
  • MariaDB Connector C, Version 2.1.0
  • TMySQL55Connection von FPC trunk und Lazarus trunk

Die Datenbanktabelle enthält binär gespeicherte GUIDs, die mit der Funktionen UuidToBin bzw. UuidFromBin konvertiert werden. Damit ich die GUIDS direkt in Pascal als Strings verarbeiten kann, habe ich mir eine Funktion PasUuidFromBin gebaut, die geschweifte Klammern hinzufügt.

Code: Alles auswählen

CREATE TABLE `data` (
   `ID` BINARY(16) NOT NULL COMMENT 'GUID',
   PRIMARY KEY (`ID`)
)
COLLATE='utf8_german2_ci'
ENGINE=InnoDB
;
-- Beispieldatensatz einfügen
INSERT INTO DATA VALUES(UuidToBin(UUID()));
-- Stored procedure um die GUIDs direkt als String auszulesen.
CREATE DEFINER=`user`@`%` FUNCTION `PasUuidFromBin`(
   `_bin` BINARY(16)
)
RETURNS char(38) CHARSET ascii
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'Retrive Pascal style UUID from binary(16)'
BEGIN
  RETURN CONCAT('{', UuidFromBin(_bin), '}');
END;

Die Datenabfrage erfolgt dann mit:

Code: Alles auswählen

SELECT PasUuidFromBin(ID) FROM DATA;

Daraus erzeugt SQLDB wie beschrieben ein Feld ftFixedChar mit der Länge 28 (TField.FSize), was dazu führt, dass nur die ersten 28 Zeichen ausgegeben werden.
Auch ein Cast die Abfrage nach CHAR(38) wird auch nicht die korrekte Länge ermittelt.

Code: Alles auswählen

SELECT CONVERT(PasUuidFromBin(ID), CHAR(38)) FROM DATA;


Weiß hier jemand weiter?

Edit: ich habe den MariaDB-Connector auf Version 3.1.0 aktualisiert und bin auf TMySQL56Connection gewechselt - keine Änderung.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Soner
Beiträge: 622
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: SQLDB und die Größe der Datenfelder (MariaDB/MySQL)

Beitrag von Soner »

Villeicht das:
SELECT CONVERT(PasUuidFromBin(ID), CHAR(38)) FROM DATA;

ändern in:
SELECT CAST(PasUuidFromBin(ID) as CHAR(38) CHARSET ascii) FROM DATA;

weil oben charset ja immer noch unbekannt ist. Es könnte utf8 oder unicode sein.

Ich frage mich wie sqldb auf 28 kommt, normalerweise multipliziert es immer mit 4 wie z.B. bei utf8-Charsets.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: SQLDB und die Größe der Datenfelder (MariaDB/MySQL)

Beitrag von Socke »

Soner hat geschrieben:SELECT CAST(PasUuidFromBin(ID) as CHAR(38) CHARSET ascii) FROM DATA;

bringt leider auch nichts, hat mich aber auf die richtige Spur geführt!

Die Eigenschaft CharSet der Verbindung war auf UTF8mb4 eingestellt, während nach Herstellen der Verbindung folgende Anweisungen ausgeführt wurden:

Code: Alles auswählen

SET CHARACTER SET `utf8`;
SET NAMES 'utf8';
SET sql_mode = ANSI_QUOTES;


Wenn das konsitent ist, d.h. sowohl per SQl als auch in den Verbindungseinstellungen die selbe Zeichenkodierung verwendet wird, wird die Länge korrekt ermittelt.
Die Länge wird übrigens in der Methode TConnectionName.MySQLDataType (generische Basisklasse für alle TMySQLNNConnection-Klassen) ausgelesen. Der Wert wird von der Datenbank vorgegeben.

Ob man UTF8 oder UTF8mb4 angibt, spielt hier keine Rolle, da alle Zeichen einer GUID in ASCII enthalten sind. Grundsätzlich sollte man aber in MySQL oder MariaDB den Zeichensatz UTF8mb4 (und zugehörige Collations) vorziehen, da dieser den gesamten Zeichenvorat abbildet. Die MySQL-Zeichenkodierung UTF8 kann maximal 3 Bytes pro Zeichen verarbeiten (während laut Unicode maximal 4 Bytes zulässig sind). Daraus können gerade aus Vergleichen sehr merkwürdige und inhaltlich fragwürdige Entscheidungen resultieren.

Der Unterschied zwischen den Einstellungen in CharSet und den SQL-Anweisungen waren übrigens genau dieser Umstellung geschuldet.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten