Добрый день.
Возникла проблема при попытке записи JPEG файла в blob поле MySQL в Лазарусе 2.0.6. под Windows 7.
Собственно запись данных в blob поле проходит, но данные приходят искаженные и по виду перекодированы.
Вот что должно быть:
яШяа JFIF яЫ C
$.' ",#(7),01444'9=82<.342яЫ C
Получаю это:
???? JFIF ?? C
$.' ",#(7),01444'9=82<.342?? C
Вроде явно указан тип ftBlob , двоичные данные, но нет где то их по пути перекодирует.
База данных старинная и проверена временем, фото от туда читаются в Лазарусе без проблем.
Текстовые поля также.
Пол дня сидел в поисковиках, но не нашел даже намека на решение проблемы.
Использую компоненты :
MySQL57Connection1: TMySQL57Connection;
SQLQuery1: TSQLQuery;
SQLTransaction1: TSQLTransaction;
код функции:
function TForm1.SavePhoto(uk: integer): boolean;
begin
Result:=False;
SQLTransaction1.Active:=False;
SQLQuery1.Clear;
SQLQuery1.SQL.Text:='update personal set photo =:BLOB_PHOTO where id = '+#39+Persons[uk].sID+#39+';';
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromFile('Photo.jpg',ftBlob);
try
SQLTransaction1.Active:=True;
except
//memo1.Lines.Add('Ошибка создания транзакции');
exit;
end;
SQLQuery1.ExecSQL;
result := SQLQuery1.RowsAffected >= -1;
if result then
SQLTransaction1.Commit
else
begin
SQLTransaction1.Rollback;
result := false;
end;
end;
Повреждение данных при записи blob поля в MySQL
Модератор: Модераторы
Я решал аналогичную задачу используя набор компонентов, идущих с Lazarus, Zeos Access. В этом наборе есть класс TBlobStream, который осуществляет корректную запись/чтение blob-полей.
Код: Выделить всё
var
BlStream : TStream;
MyBitmap : TBitmap;
begin
...
BlStream := CreateBlobStream(FieldByName('PASS_COPY'),bmWrite) ;
MyBitmap.SaveToStream(BlStream) ;
BlStream.Free ;
...
end;
Lekur писал(а):Вроде явно указан тип ftBlob , двоичные данные, но нет где то их по пути перекодирует.
Скорее Blob поле открывается TStringStream и обрабатывается как String значение, отсюда Char "?" вместо Byte $XX.
Почему так? наверно есть поля Text которые по сути Blob-ы, раз нужно вывести в DBGrid - то выводится дефолтно как String
Поэтому надо работать через TStream(TStreamMemory/TSreamFile ..)
Если Blob-поле обрабатывается как String, то попробуйте использовать quoted string. В модуле sysutils есть соответствующая функция
Код: Выделить всё
function QuotedStr(
const S: string
):string;Использование TStringStream не помогло , результат тот же. Похоже как и чем положены данные в blob SQLQuery не важно, при транзакции они по любому воспринимаются как текстовые и перекодируются. С просмотром данных проблем нет, то что пишет в базу я смотрю HeidiSQL.
Переходить на другие компоненты, возможно выход, но уже часть проекта на родных компонентах и довольно много, есть смысл ещё покапать.
Полагаю копать надо в сторону параметров ftGraphic и возможно исходников SQLQuery:
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftBlob); //Портит данные
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftMemo); //Портит данные
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftGraphic); //Ругается на формат данных
var
tMs:TMemoryStream;
tSs:TStringStream;
begin
Result:=False;
Image1.Picture.LoadFromFile('Photo.jpg');
try
tMs:=TMemoryStream.Create;
tsS:=TStringStream.Create('');
tMs.LoadFromFile('Photo.jpg');
tMs.Position:=0;
tsS.CopyFrom(tMs,tMs.Size);
SQLQuery1.SQL.Text:='update personal set photo =:BLOB_PHOTO where id = '+#39+sID+#39+';';
SQLQuery1.ParamByName('BLOB_PHOTO').asBlob := tsS.DataString;
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
Добавлено спустя 5 часов 41 минуту 49 секунд:
Написал проверочную функцию на ZeosLib. В таком виде все работает корректно, пишет в базу правильно.
Вопрос, в чем косяк в стандартных компонентах остался. Я пробовал откатится на старые dll, со старыми компонентами 5.5. но не помогло.
В ZConnection есть по умолчанию отключенная опция AutoEncodingString, проверять не стал.
function TForm1.PhotoToSCUD(uk: integer): boolean;
var
tMs:TMemoryStream;
begin
Result:=False;
Image1.Picture.LoadFromFile('Photo.jpg');
try
tMs:=TMemoryStream.Create;
tMs.LoadFromFile('Photo.jpg');
tMs.Position:=0;
ZQuery2.SQL.clear;
Zconnection1.AutoCommit:=false;
ZQuery2.SQL.Text:='update personal set photo =:BLOB_PHOTO where id = '+#39+'3c17dbd2-a6fc-11e0-b5e4-0050568e4f6c'+#39+';';
ZQuery2.ParamByName('BLOB_PHOTO').SetBlobData(tMs.Memory,tMs.Size);
ZQuery2.execsql;
Zconnection1.Commit;
ZConnection1.AutoCommit:=true;
finally
tMs.Free;
end;
end;
Переходить на другие компоненты, возможно выход, но уже часть проекта на родных компонентах и довольно много, есть смысл ещё покапать.
Полагаю копать надо в сторону параметров ftGraphic и возможно исходников SQLQuery:
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftBlob); //Портит данные
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftMemo); //Портит данные
SQLQuery1.ParamByName('BLOB_PHOTO').LoadFromStream(tMs , ftGraphic); //Ругается на формат данных
var
tMs:TMemoryStream;
tSs:TStringStream;
begin
Result:=False;
Image1.Picture.LoadFromFile('Photo.jpg');
try
tMs:=TMemoryStream.Create;
tsS:=TStringStream.Create('');
tMs.LoadFromFile('Photo.jpg');
tMs.Position:=0;
tsS.CopyFrom(tMs,tMs.Size);
SQLQuery1.SQL.Text:='update personal set photo =:BLOB_PHOTO where id = '+#39+sID+#39+';';
SQLQuery1.ParamByName('BLOB_PHOTO').asBlob := tsS.DataString;
SQLQuery1.ExecSQL;
SQLTransaction1.Commit;
Добавлено спустя 5 часов 41 минуту 49 секунд:
Написал проверочную функцию на ZeosLib. В таком виде все работает корректно, пишет в базу правильно.
Вопрос, в чем косяк в стандартных компонентах остался. Я пробовал откатится на старые dll, со старыми компонентами 5.5. но не помогло.
В ZConnection есть по умолчанию отключенная опция AutoEncodingString, проверять не стал.
function TForm1.PhotoToSCUD(uk: integer): boolean;
var
tMs:TMemoryStream;
begin
Result:=False;
Image1.Picture.LoadFromFile('Photo.jpg');
try
tMs:=TMemoryStream.Create;
tMs.LoadFromFile('Photo.jpg');
tMs.Position:=0;
ZQuery2.SQL.clear;
Zconnection1.AutoCommit:=false;
ZQuery2.SQL.Text:='update personal set photo =:BLOB_PHOTO where id = '+#39+'3c17dbd2-a6fc-11e0-b5e4-0050568e4f6c'+#39+';';
ZQuery2.ParamByName('BLOB_PHOTO').SetBlobData(tMs.Memory,tMs.Size);
ZQuery2.execsql;
Zconnection1.Commit;
ZConnection1.AutoCommit:=true;
finally
tMs.Free;
end;
end;
Старанно конечно. Компоненты по умполчанию не без греха конечно, но работают вроде.
Ради теста не поленился накатал такой код.
Загрузил картинку , выгрузил, ни байта не изменилось.
Добавлено спустя 1 минуту 41 секунду:
Структура таблицы
Ради теста не поленился накатал такой код.
Код: Выделить всё
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, mysql56conn, sqldb, Forms, Controls, Graphics, Dialogs,
StdCtrls, db;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
MS: TMySQL56Connection;
OpenDialog1: TOpenDialog;
SQLQuery1: TSQLQuery;
SQLTransaction1: TSQLTransaction;
procedure Button1Click(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
ms.HostName:='localhost';
ms.DatabaseName:='test';
ms.UserName:='еуые';
ms.Password:='еуые';
ms.Port:=3306;
ms.Connected:=true;
SQLQuery1.SQL.Text:='INSERT INTO table1(myblob) VALUES (:myblob);';
SQLQuery1.ParamByName('myblob').LoadFromFile(OpenDialog1.FileName, ftBlob);
SQLQuery1.ExecSQL;
ms.Transaction.Commit;
end;
end;
end.
Загрузил картинку , выгрузил, ни байта не изменилось.
Добавлено спустя 1 минуту 41 секунду:
Структура таблицы
Код: Выделить всё
CREATE TABLE test.table1 (
id int(11) NOT NULL AUTO_INCREMENT,
myblob longblob DEFAULT NULL,
PRIMARY KEY (id)
)
ENGINE = INNODB,
CHARACTER SET latin1,
COLLATE latin1_swedish_ci;У вас нет необходимых прав для просмотра вложений в этом сообщении.
