Lazarus

BLOB-поле в MySQL, Lazarus, работа напрямую через LibMySQL.dll

Автор: GAMER вкл. .

 

Так, как работаю через LibMySQL.dll, и при этом ничего другого не использую, то столкнулся с проблемой записи и чтения данных с BLOB-поля.

Сначала о граблях.
1. Основные грабли - это нулевые символы в данных. При работе с PChar, AnsiString получаем кучу гемора.
2. Нужно быть очень аккуратными при работе с MemoryStreamN.Write
3. Нужно аккуратно использовать mysql_real_escape_string. Оно преобразовывает все, в том числе и те кавычки, которые не нужно було :) Долго с этим возился :)
4. При анализе данных в watch-окне, в строках фигурируют вопросительные знаки. Это все UTF8. Нужно побайтно просматривать.

Что нужно (желательно) использовать.
1. В запросах делаем CAST("...'" as binary)
2. Служебные символы Мускуля обходим с помощью mysql_real_escape_string, но аккуратно.
3. Размер вывода получаем через mysql_fetch_lengths(PResult) (другие функции обрезают длину по нулевому символу.)

Примеры:
Подпрограмма записи в блоб-поле:

Function QuerryP(Const MySock : PMYSQL; Const SelStr: PChar; Const len: longint; Out MySQLErrMsg : AnsiString): boolean;
Begin
Result := True;
if (mysql_real_query(MySock,SelStr, len) <> 0) then
begin
MySQLErrMsg := 'Query failed. '+ mysql_error(MySock);
Result := False;
exit;
end;
End;

Подпрограмма формирования запроса для записи:

procedure TFrmWebcam.Button2Click(Sender: TObject);
const S1='insert into foto set unsprava=1, foto=CAST("';
S2='" as binary)';
var
Stream: TMemoryStream;
w1, w2: Pchar;
begin
// Image1.Picture.Jpeg.SaveToFile('test.jpg');
Stream := TMemoryStream.Create;
// Image1.Picture.Jpeg.SetSize(10,10);
Image1.Picture.Jpeg.SaveToStream(Stream);  // Сохраняем Jpeg-картинку в поток
Stream.Position:=0;
GetMem(w1, Stream.Size);
Stream.Read(w1[0], Stream.Size); // Читаем с потока  в переменную w1
GetMem(w2, 2*Stream.Size);
mysql_real_escape_string(MySockW, w2, w1, Stream.Size); //Делаем читабельную для Мускуля строку
Stream.Free;
if not QuerryP(MySockW, Pchar(s1+w2+s2), Length(s1+w2+s2), ErrMsg) then ShowMessage(ErrMsg);
Freemem(w1);Freemem(w2);
end;

Подпрограмма чтения блоб-поля:

Function SelectToMemoryStream(Const Mysock: PMYSQL; Const SelStr: AnsiString;
 Var MemoryStreamN: TMemoryStream; Out VMySQLErrMsg : AnsiString): boolean;
Var FieldCount: Integer;
PCurrentRow: {$IFDEF FPC}MySQL_Row{$ELSE}PMySQL_Row{$ENDIF};
PResult: Pointer;
RecordCount:  Integer;
LenArray: PDWord;
Begin
Result := True;
if (mysql_query(MySock,PChar(SelStr)) > 0) then
begin
VMySQLErrMsg := 'Ошибка запроса. '+ mysql_error(MySock);
Result := False;
exit;
end;
PResult:= MySQL_Use_Result(MySock); {Can be called for select and none-select.
 Returns nil if storing failed or if query was none-select}
if PResult = nil then
begin
if MySQL_Field_Count(MySock) = 0 then {It was a none-select}
begin
VMySQLErrMsg := 'Запрос не возвратил поля. '+chr(10)+chr(13)+
'Обработано '+IntToStr(MySQL_Affected_Rows(MySock))+' записей.';

Result := False;
exit;
end
else {It was a select query, but an error has occured}
begin
VMySQLErrMsg := 'Ошибка запроса. '+ mysql_error(MySock);
Result := False;
exit;
end;
end;
// else Result is not null - receiving data
try
// Fields count receiving
FieldCount:= MySQL_Num_Fields(PResult);
if (FieldCount=0) or (FieldCount>1) then
begin
VMySQLErrMsg := 'Запрос не возвратил поля либо полей больше 1';
Result := False;
exit;
end;
// Record data receiving
RecordCount := 0;
PCurrentRow:= MySQL_Fetch_Row(PResult);
LenArray:=mysql_fetch_lengths(PResult);
while PCurrentRow <> nil do
begin
Inc(RecordCount);
MemoryStreamN.Position:=0;
MemoryStreamN.Write(PCurrentRow[0][0], LenArray[0]);
PCurrentRow:= MySQL_Fetch_Row(PResult);
end;
finally
MySQL_Free_Result(PResult);
PResult:=nil;
PCurrentRow:=nil;
end;
End;

Подпрограмма формирования запроса и вставки картинки:

procedure TFrmWebcam.Button3Click(Sender: TObject);
Var  Stream: TMemoryStream;
Begin
Stream := TMemoryStream.Create;
if not SelectToMemoryStream(MySockW,
'select CAST(foto as binary) from foto',
Stream, ErrMsg) then
ShowMessage(ErrMsg)
else
begin
Stream.Position:=0;
Image1.Picture.Jpeg.LoadFromStream(Stream);
end;
Stream.Free;
End;