Работа с BLOB через IBX
Модератор: kdv
Работа с BLOB через IBX
Использую IBQUERY для вставки записи:
пишу в .SQL:
insert into FILES (FILE_ID,FILE_DATA) values (:FILE_ID,:FILE_DATA)'
где FILE_DATA BLOB SUB_TYPE 0
Значение FILE_ID получаю темже IBQUERY чуть выше из генератора в
var NewFileID:Int64;
Передаю "динамически" в запрос:
IBQuery1.ParamByName('FILE_ID').AsInteger:=NewFileID;
А вот что делать с FILE_DATA - понятия не имею, потому как у меня он в TIBBlobStream.
Да можно попросту создать запись а потом "модифнуть" его IBDATASET ом. Но хочеться одним запросом и FILE_ID и FILE_DATA.
Как это реализовать?
PS1:TIBBlobStream изпользую потому как шифрую данные.
PS1: И вообще где достать нормальную документацию по использованию IBX 7.11. Во всех книгах одна фигня...
пишу в .SQL:
insert into FILES (FILE_ID,FILE_DATA) values (:FILE_ID,:FILE_DATA)'
где FILE_DATA BLOB SUB_TYPE 0
Значение FILE_ID получаю темже IBQUERY чуть выше из генератора в
var NewFileID:Int64;
Передаю "динамически" в запрос:
IBQuery1.ParamByName('FILE_ID').AsInteger:=NewFileID;
А вот что делать с FILE_DATA - понятия не имею, потому как у меня он в TIBBlobStream.
Да можно попросту создать запись а потом "модифнуть" его IBDATASET ом. Но хочеться одним запросом и FILE_ID и FILE_DATA.
Как это реализовать?
PS1:TIBBlobStream изпользую потому как шифрую данные.
PS1: И вообще где достать нормальную документацию по использованию IBX 7.11. Во всех книгах одна фигня...
Читал перед тем как задал тему.WildSery писал(а):Тут читал?
Ну вот от туда:
IBQuery1.ParamByName('blb').asBlob:=blobvar;
Ну и как мне в строку записать 1Гб из потока?
А понял!
Прокритикуйте плиз:
Прокритикуйте плиз:
Код: Выделить всё
procedure TForm1.BitBtn6Click(Sender: TObject);
var NewFileID:int64;
begin
if IBDatabase1.Connected then
if OpenDialog1.Execute then
begin
try
IBTransaction1.RollbackRetaining;
//Получаем значения генератора
IBQuery1.Close;
IBQuery1.SQL.Clear;
IBQuery1.SQL.Add('select GEN_ID(GEN_FILE_ID,1) from RDB$DATABASE');
IBQuery1.Open;
NewFileID:=IBQuery1.FieldByName('GEN_ID').AsVariant;
//Загружаем в поток данные файла
ActiveBlob:=TIBBlobStream.Create;
ActiveBlob.Mode:=bmReadWrite;
ActiveBlob.LoadFromFile(OpenDialog1.FileName);
//Делаем всякую фигню
//формируем запрос на добавление записи
IBQuery1.Close;
IBQuery1.SQL.Clear;
IBQuery1.SQL.Add('insert into FILES (FILE_ID,FILE_DATA) values (:FILE_ID,:FILE_DATA)');
IBQuery1.ParamByName('FILE_ID').AsInteger:=NewFileID;
IBQuery1.ParamByName('FILE_DATA').LoadFromStream(ActiveBlob,ftBlob);
IBQuery1.Open;
IBTransaction1.CommitRetaining;
ActiveBlob.Free;
except
IBTransaction1.RollbackRetaining;
ActiveBlob.Free;
end;
end;
end;
-
- Сообщения: 144
- Зарегистрирован: 16 фев 2006, 22:36
Это пожалуйста.kostyl писал(а):Прокритикуйте плиз:
1) Конечно, ничто так не повышает читаемость кода, как отсутствие тега Code
2)
Код: Выделить всё
try
IBTransaction1.RollbackRetaining;
3)
Код: Выделить всё
NewFileID:=IBQuery1.FieldByName('GEN_ID').AsVariant;
...
IBQuery1.ParamByName('FILE_ID').AsInteger:=NewFileID;
Вместо IBQuery здесь лучше использовать IBSQL - он легче, и есть поддержка BIGINT. Если NewFileID в коде больше нигде не используется, можно от него избавиться:
Код: Выделить всё
insert into FILES (FILE_ID,FILE_DATA)
values ( GEN_ID(GEN_FILE_ID,1),:FILE_DATA)
Код: Выделить всё
try
...
except
IBTransaction1.RollbackRetaining;
ActiveBlob.Free;
end;
5) С ActiveBlob лучше поступить так:
Код: Выделить всё
ActiveBlob:=TIBBlobStream.Create;
try
// Работаем с ActiveBlob
finally
FreeAndNil(ActiveBlob);
end;
...
IBTransaction1.CommitRetaining;
Код: Выделить всё
procedure TForm1.BitBtn6Click(Sender: TObject);
begin
if IBDatabase1.Connected then
if OpenDialog1.Execute then
DoSaveBlob(OpenDialog1.FileName);
end;
тут и критиковать нечего. ужасные действия в коде.
кроме того, нифига ж не читал, если сначала Post, а потом Free.
кстати, была дока - в хелпе D7, отдельным файлом. Но увы.
Кстати. как работать - есть описание в developer guide по дельфям.
кроме того, нифига ж не читал, если сначала Post, а потом Free.
документация не нужна. есть ibx.htm.И вообще где достать нормальную документацию по использованию IBX 7.11. Во всех книгах одна фигня...
кстати, была дока - в хелпе D7, отдельным файлом. Но увы.
Кстати. как работать - есть описание в developer guide по дельфям.
-
- Сообщения: 144
- Зарегистрирован: 16 фев 2006, 22:36
Доброго времени суток!
В TIBXSQLVAR.LoadFromStream создается и уничтожается временный TIBBlobStream, так что вроде бы ничего страшного.
Кстати, а в силу чего такой запрет (статью я читал )?
Физическая запись BLOB происходит при Post, и если мы убъем TIBBlobStream раньше, то он будет закрыт и не сохранен в БД?
Загрузка через LoadFromStream ведется в параметр (т.е. TIBXSQLVAR), а не в TIBBlobStream непосредственно.kdv писал(а):кроме того, нифига ж не читал, если сначала Post, а потом Free.
В TIBXSQLVAR.LoadFromStream создается и уничтожается временный TIBBlobStream, так что вроде бы ничего страшного.
Кстати, а в силу чего такой запрет (статью я читал )?
Физическая запись BLOB происходит при Post, и если мы убъем TIBBlobStream раньше, то он будет закрыт и не сохранен в БД?
а пофиг. есть такое правило кодирования - ресурсы освобождаются в том порядке, в котором они аллокируются.Физическая запись BLOB происходит при Post, и если мы убъем TIBBlobStream раньше, то он будет закрыт и не сохранен в БД?
ты уверен? код IBX смотрел?Физическая запись BLOB происходит при Post, и если мы убъем TIBBlobStream раньше
-
- Сообщения: 144
- Зарегистрирован: 16 фев 2006, 22:36
Доброго времени суток!
Там знак вопроса стоял.
WriteBlob вызывается только в TIBXSQLVAR.Assign (кажется, не используется) и в TIBBlobStream.Finalize. Последний вызывается в TIBCustomDataSet.InternalPostRecord, TIBBlobStream.CloseBlob, TIBXSQLVAR.LoadFromStream.
CloseBlob не используется, InternalPostRecord вызывается при Post,
LoadFromStream вызывается в TIBCustomDataSet.InternalSetParamsFromCursor,
TIBXSQLVAR.SetAsString
Поэтому неясно, рабочий ли код:
Возможно, я что-то не учел?
В обратном Правда, не вижу связи с данным случаем.kdv писал(а):а пофиг. есть такое правило кодирования - ресурсы освобождаются в том порядке, в котором они аллокируются.
ты уверен?
Там знак вопроса стоял.
В TIBBlobStream.Destroy есть только isc_close_blob - закрытие BLOB. isc_put_segment встречается только в IBBlob.WriteBlobкод IBX смотрел?
WriteBlob вызывается только в TIBXSQLVAR.Assign (кажется, не используется) и в TIBBlobStream.Finalize. Последний вызывается в TIBCustomDataSet.InternalPostRecord, TIBBlobStream.CloseBlob, TIBXSQLVAR.LoadFromStream.
CloseBlob не используется, InternalPostRecord вызывается при Post,
LoadFromStream вызывается в TIBCustomDataSet.InternalSetParamsFromCursor,
TIBXSQLVAR.SetAsString
Поэтому неясно, рабочий ли код:
Код: Выделить всё
IBDataSet1.Edit;
B:=IBDataSet1.CreateBlobStream(IBDataSet1.FieldByName('BLB') as TBlobField, bmWrite);
B.LoadFromFile('c:\blob.bin');
B.Free;
IBDataSet1.Post;
Огромное спасибо за коментарии. Почувствовать себя немощьным новичком - великое благо ибо оно стимулирует на большие подвиги.
P.S.:А вообщем хорошо, что есть такой сайт как этот, хотя всё равно трудно идёт "разбор" с клиент-сервером, как с непознанным доселе. Сейчас активно изучал статью про транзакции. Довольно сложно разобраться со всеми блокировками, параметрами, хоть там и даны маленькие примеры в конце, которые могут подойти, но хотелось бы по конкретнее - на реальном примере. Все равно большое спасибо. Вот подучусь и напишу новую версию кода.
А. Так и не поругал....kdv писал(а):Читал, да наверно значение на предал. Виноват.нифига ж не читал, если сначала Post, а потом FreeКузнецов Евгений писал(а):Ну а за Retaining Вас KDV поругает, когда вернется
P.S.:А вообщем хорошо, что есть такой сайт как этот, хотя всё равно трудно идёт "разбор" с клиент-сервером, как с непознанным доселе. Сейчас активно изучал статью про транзакции. Довольно сложно разобраться со всеми блокировками, параметрами, хоть там и даны маленькие примеры в конце, которые могут подойти, но хотелось бы по конкретнее - на реальном примере. Все равно большое спасибо. Вот подучусь и напишу новую версию кода.
а мне уже до лампочки. в статьях по транзакциям на сайте про retaining как на каждом столбе написано.А. Так и не поругал...
на реальном примере нужны только 2 типа транзакций, это по минимуму. read_committed rec_version nowait для просмотра ино хотелось бы по конкретнее - на реальном примере.
concurrency nowait например для отчетов
все остальное - по вкусу и по ситуации. Читать - это правильно, причем не один раз, а пока дойдет. Я исходную доку по транзакциям IB 4.0 читал раз 5-6, пока дошло. Это при том что там страниц 10 всего (или меньше).
перед вставкой в FAQ я код проверял. ты тоже можешь проверить - всего-то две строчки местами переставить. Проверил-бы и уличил меня, если я неправ. Мало-ли что.Поэтому неясно, рабочий ли код:
Я вот почему-то помню, что если Free ставили после Post, то были глюки, особенно в BDE. Отсюда и рекомендация.
-
- Сообщения: 144
- Зарегистрирован: 16 фев 2006, 22:36
Доброго времени суток!
Насколько я понял, в 6.08 CreateBlobStream возвращает не TIBBlobStream как раньше, а его достаточно беззубую обертку TIBDSBlobStream. LoadFromFile в последнем не реализован, поэтому для чтения из файла придется создавать дополнительный поток
Так как в деструкторе класса TIBDSBlobStream сам TIBBlobStream не уничтожается (утечка памяти тут не грозит, поскольку TIBBlobStream хранится во внутреннем списке IBDataset.FBlobStreamList, который убивается при закрытии IBDataset), то особой разницы, где именно вызывать Post, нет - эксперимент показал успешность обоих вариантов.
Единственное отличие может быть только, если используются DB-Aware компоненты для отображения BLOB - деструктор TIBDSBlobStream посылает событие об изменении BLOB-поля, поэтому в этом случае логичнее делать Post после освобождения B.
Не в чем Вас уличать Написано же,kdv писал(а):перед вставкой в FAQ я код проверял. ты тоже можешь проверить - всего-то две строчки местами переставить. Проверил-бы и уличил меня, если я неправ. Мало-ли что.
Естественно, копание в IBX 6.08 ничего не скажет о работоспособности ранних версий.Статья писал(а):В предыдущих версиях IBX (до 4.42 включительно) можно было работать с blob иначе.
Насколько я понял, в 6.08 CreateBlobStream возвращает не TIBBlobStream как раньше, а его достаточно беззубую обертку TIBDSBlobStream. LoadFromFile в последнем не реализован, поэтому для чтения из файла придется создавать дополнительный поток
Код: Выделить всё
var B: TIBDSBlobStream;
fs:TFileStream;
begin
IBDataSet1.Edit;
B:=IBDataSet1.CreateBlobStream(IBDataSet1.FieldByName('DATA') as TBlobField, bmWrite) as TIBDSBlobStream;
try
fs:=TFileStream.Create('c:\blob.bin',fmOpenRead);
try
B.CopyFrom(fs,fs.Size)
finally
FreeAndNil(fs);
end;
IBDataSet1.Post;
finally
FreeAndNil(B);
end;
//IBDataSet1.Post;
end;
Единственное отличие может быть только, если используются DB-Aware компоненты для отображения BLOB - деструктор TIBDSBlobStream посылает событие об изменении BLOB-поля, поэтому в этом случае логичнее делать Post после освобождения B.
"хочеться" с мягким знаком, потому как "непонимать" в инфинитиве и слитно. Вот. А еще такой вопрос - что вы подразумеваете под словом "АЛЛОКИРУЕТСЯ" - привязывается или как. лок вроде замок. а значит замыкается. или как?kdv писал(а):мне больше интересно, почему "вызывается" без мягкого знака, а "хочеться" - с мягким знаком. Ты уж определись, пожалуйста. Или ставь его везде, или только там где надо.
с мягким знаком пишут хотеться, а не хочетсяkostyl писал(а):"хочеться" с мягким знаком, потому как "непонимать" в инфинитиве и слитно. Вот. А еще такой вопрос - что вы подразумеваете под словом "АЛЛОКИРУЕТСЯ" - привязывается или как. лок вроде замок. а значит замыкается. или как?kdv писал(а):мне больше интересно, почему "вызывается" без мягкого знака, а "хочеться" - с мягким знаком. Ты уж определись, пожалуйста. Или ставь его везде, или только там где надо.
аллокировать в данном случае - выделять