Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2006.08.06;
Скачать: [xml.tar.bz2];

Вниз

Работа с полем BLOB, очень жду   Найти похожие ветки 

 
Romul   (2006-05-30 17:31) [0]

Связка слудующая:
D7 + ADO + MyODBC3.51 + MySQL5,0

Есть таблица в которой есть поле BLOB.
Когда в датасете стоит ftBlob и есть данные то делфи ругается на то что в реально передается varbyte, а ожидается blob,
Когда тип поля ставиш varbyte то у делфи начинается кризис с размерностью данных, типа того размер установлен 10000, а на самом деле 980...
А если нет данных то ругается на то, что  стоит VarByte, а на самом деле возвращается Blob...
Подскажите может кто уже решал подобную проблему?
Blob используется для храниния FastReport отчетов.


 
Romul   (2006-05-30 20:55) [1]

Добавлю.
То же самое происходит и с полями типа TEXT
Если нет данных до Делфи опознает их как memo
а при запросе данных сообщает что фактически возвращается string
А если используется блоб то то он опознает их как VarByte.
Подскажите в каком направлении рыть?
Или может кто подскажет компоненты для работы с MySQL, при чем желательно чтобы была нормальная работа с БЛОБ


 
Romul   (2006-05-31 12:02) [2]

Подскажите хотябы компонент в котором можно спокойно работать с blob полями...
Плиззззз....


 
Johnmen ©   (2006-05-31 12:21) [3]

TBlobField, TBlobStream, TADOBlobStream etc.


 
Romul   (2006-05-31 15:40) [4]

Если не секрет, то как мне при помощи того что вы указали избвится от переконвертации, которая происходит при установке поля типа blob?
Если в ADODataSet добавить поле, которое в базе MySQL5.0 хранится как blob, и указать в датасете при добавлении поля тип blob, то при отсутствии данных в этом поле все проходит нормально, но после того к в этом поле появились данные возникает ошибка: Type mistmach for field "FieldName" expecting:"Blob" actual "VarBytes".
Такая же фигня происходит и с полями типа ТЕХТ


 
Romul   (2006-05-31 15:41) [5]

Забыл добавить, ошибка возникает при открытии датасета


 
sniknik ©   (2006-05-31 15:53) [6]

не надо ставить у поля параметры отличные от типа поля в базе(таблице), их вообще не надо выставлять, создавать поле, если само оно не нужно, типы получаются при запросе, правильные.


 
Romul   (2006-05-31 16:04) [7]

При запросе они и устанавливаются в те, которые стоят в базе, и при открытии без данных они не вызывают ошибки, а если в этом поле появились данные, то тогда и возникает ошибка.


 
sniknik ©   (2006-05-31 16:10) [8]

> При запросе они и устанавливаются в те, которые стоят в базе
отлично! и зачем же тогда типу уже имеющему значение ftBlob еще раз устанавливать ftBlob? что от этого меняется?
смысла нет.
т.е. либо ты  меняеш на другой, априори неверный тип, либо ошибка в чемто другом. (в 17-й строке например)


 
Romul   (2006-05-31 16:41) [9]

По желаниям трудящихся прилагаю "17 строку кода"
Обращение к ADOQuery

 DMMain.qryGetReports.Close;
 DMMain.qryGetReports.Parameters.ParamByName("FName").Value:=FromForm;
 DMMain.qryGetReports.ExecSQL;
 DMMain.qryGetReports.Open;
 frReport.LoadFromBlobField(DMMain.qryGetReportsRepData);
 frReport.PrepareReport;
 frReport.ShowReport;


Текст запроса

Select * from reports
where FormName=:FName


Скрипт создающий таблицу в БД

DROP TABLE IF EXISTS `reports`;
CREATE TABLE `reports` (
 `ID` int(10) unsigned NOT NULL auto_increment,
 `ReportName` varchar(100) NOT NULL default "",
 `RepData` blob,
 `ReportQuery` varchar(500) NOT NULL default "",
 `FormName` varchar(45) NOT NULL default "",
 PRIMARY KEY  (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=cp1251;

Создание полей в ADOQuery делаю следующим образом:
Кидаю qry на форму, заполняю SQL, двойной щелчек, Add all fields. и все.

Ошибка возникает на строке DMMain.qryGetReports.Open;


 
sniknik ©   (2006-05-31 17:27) [10]

> По желаниям трудящихся прилагаю "17 строку кода"
> Обращение к ADOQuery
и сразу же стало на "полшага" понятнее

> DMMain.qryGetReports.ExecSQL;
вот это глюк. раз.
или ExecSQL или Open, а еще лучше перейди на родные ADODataSet, ADOCommand у них четкое деление возвращающие/невозвращающие рекордсет запросы.

> frReport.LoadFromBlobField(DMMain.qryGetReportsRepData);
> frReport.PrepareReport;
> frReport.ShowReport;
вот это убери... пока, хотя бы.  ты же "грешиш" на ADO, а тут лишняя сущность, лучше добавь дбгрид и "привяжи" его к рекордсету для визуальности того что получаеш. работает?

все поля в дизайне созднные тоже убери. и т.д. ничего лишнего, кроме тестируемого ничего не должно остатся. после понемногу будеш добавлять/восстанавливать.


 
Romul   (2006-05-31 17:43) [11]

Если без предварительного объявления полей все делать, то возникает ошибка InvalidTypeCast при обращении к Blob полю как к потоку(TMemoryStream)


 
Romul   (2006-05-31 17:47) [12]

Опять же это возникает когда данные есть базе, если их нет то все проходит великолепно


 
sniknik ©   (2006-05-31 18:01) [13]

> при обращении к Blob полю как к потоку(TMemoryStream)
а ты не обращайся... говорил же поставь грид, он тоже обращается. он работает? а у тебя значит неправильно.  (естественно неправильно если "к Blob полю как к потоку(TMemoryStream)", надо не конвертить обращаясь как, а в поток из поля копировать... но это уже забегание вперед, обсуждение второй 17й строки не видя ее...)


 
Romul   (2006-05-31 19:39) [14]

Хорошо, тогда выдрав кусок из fastreport копирования в stream делаю по образу и подобию

 DMMain.qryGetReports.Close;
 DMMain.qryGetReports.Parameters.ParamByName("FName").Value:=FromForm;
 DMMain.qryGetReports.Open;

 Stream := TADOBlobStream.Create(TBlobField(DMMain.qryGetReports.FieldByName("RepData")), bmRead);

 try
   Stream.Position := 0;
   frReport.LoadFromStream(Stream);
 finally
   Stream.Free;
 end;


и прога ругается следующим образом на строчке  Stream := TADOBlobStream.Create:
сначала
InvalidArgument
потом
InvalidVariantType

что то у меня такое ощущение что я не в ту сторону капаю....


 
sniknik ©   (2006-05-31 20:34) [15]

> Stream := TADOBlobStream.Create(TBlobField(DMMain.qryGetReports.FieldByName("RepData")), bmRead);
вот это правильно, можно так, даже перепроверил... (правда на access, MySQL-я счас не стоит, но должно быть не важно)
совершенно непонятно почему неверный аргумент(InvalidArgument)... может у тебя используется модуль какой нибудь в котором TADOBlobStream или TBlobField перекрыт? в том же модуле репорта который я просил убрать (вообще ничего лишнего!)

> потом
> InvalidVariantType
а вот это скорее всего на чтении происходит, ну вообщето непонятно создался поток или нет от предыдущей ошибки... но если создался то еще глюк, чтение из NULL поля, надо проверять.
try
 if Stream.Size <> 0 then begin
   Stream.Position := 0;
   frReport.LoadFromStream(Stream);
 end;
finally
  Stream.Free;
end;

и вообще убери все, все лишнее, вообще. оставь минимум и только стандартное, новый проект, форму, пару ADO компонент (кстати я не пользуюсь ADOQuery (и не буду!), а только ADODataSet-ом, проверял на нем (1й абзац)), копируй не в репорт, а в файловый поток к примеру (он стандартный)...

FileStream:= TFileStream.Create("путь и файл какой нибудь", fmCreate or fmShareDenyRead);
try
 if Stream.Size <> 0 then begin
   Stream.Position:= 0;
   FileStream.CopyFrom(Stream, Stream.Size);
 end;
finally
  Stream.Free;
end;
ну типа того, по кнопке выполнить, руботает?... а то уже начали разные нехорошие подозрения по поводу репорта возникать...


 
sniknik ©   (2006-05-31 21:09) [16]

+
> Кидаю qry на форму, заполняю SQL, двойной щелчек, Add all fields. и все.
какого типа определяется/создается поле RepData? TBlobField надеюсь? т.е. что после этого записалось в описание класса формы.


 
Romul   (2006-06-01 01:22) [17]


procedure TForm1.Button1Click(Sender: TObject);
var BField: TBlobField;
begin
BField:=TBlobField(ADODataSet1.FieldByName("RepData"));
Stream := TADOBlobStream.Create(BField, bmRead);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 FileStream:= TFileStream.Create("c:\test.dat", fmCreate or fmShareDenyRead);
 try
   if Stream.Size <> 0 then
   begin
     Stream.Position:= 0;
     FileStream.CopyFrom(Stream, Stream.Size);
   end;
 finally
   Stream.Free;
 end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 ADODataSet1.Open;
 ADODataSet1.Edit;
 if ADODataSet1.FieldByName("RepData").IsBlob then
 Label1.Caption:="blob";
end;

procedure TForm1.Button4Click(Sender: TObject);
var  FileStream1: TFileStream;
begin
 FileStream1:= TFileStream.Create("c:\up.sql", fmOpenRead or fmShareDenyRead);
 Stream.CopyFrom(FileStream1, FileStream1.Size);
 FileStream1.Free;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
 ADODataSet1.Post;
end;


После первого сохранения любых данных поле перестает опознаваться как blob оно становится VarByte....


 
sniknik ©   (2006-06-01 09:10) [18]

> оно становится VarByte....
это козни дьявола, не иначе... пригласи священника на крестный ход, пусть по квартире походит, монитор святой водой окропит, бесовская сила из него и уйдет...

p.s. я так понял чтение уже нормально проходит? т.е. первоначальная "проблема" устранена? ну и с этим теперь тоже разбирайся...


 
Romul   (2006-06-01 10:32) [19]

Чтение происходит нормально только в том случе если данных в блоб поле нет, если они есть то возникает InvalidArgument


 
sniknik ©   (2006-06-01 11:21) [20]

> если они есть то возникает InvalidArgument
значит поле в базе не блоб, других вариантов нет. может в MySql под типом blob чтото другое понимается... или есть различия у самого типа.

хотя нет, есть еще вариант, "чудит" провайдер данных (MyODBC3.51), "заточен" под чтото другое, а данных для ADO полностью не предоставляет.


 
Romul   (2006-06-01 13:16) [21]

Решил попробовать добавлять значения через Insert и возник очередной вопрос:
Как можно параметру в запросе передать БЛОБ.
ADO параметры не поддерживают LoadFromStream, но за то им можно присвоить уже установленные данные из другого TParameters вот тут возникает еще один вопрос как сделать свой элемент класса TParameters?


 
sniknik ©   (2006-06-01 13:25) [22]

> ADO параметры не поддерживают LoadFromStream
что значит не поддерживают??? знаеш если ты любое свое незнание, неспосбность найти (в очевидном надо сказать месте), будеш "обьяснять" подобным образом... далеко не "уедеш".

> как сделать свой элемент класса TParameters?
ну отбросив то что на самом деле это не нужно, отвечая буквально, то также как все остальные элементы классов TParameters.Create(...);


 
Romul   (2006-06-01 13:27) [23]

Примерная проблема обсуждалась на форуме MySQL
http://forums.mysql.com/read.php?49,79243,84633#msg-84633
Но вот только у меня возникли вопросы как это можно сделать в реалии?


 
Romul   (2006-06-01 13:38) [24]

Хорошо, может тогда сможете объяснить такой трюк хелпа:
Находим TCustomADODataSet -> Properties -> Parameters -> TParameters->Methods

и тут мы не видим ни одной ссылки на методы типа LoadFrom....


 
Romul   (2006-06-01 13:40) [25]

Пардон, нашел


 
sniknik ©   (2006-06-01 13:50) [26]

> Примерная проблема обсуждалась на форуме MySQL
> ...
эта "проблема" рядом с твоей "и близко не лежала", там обсуждают как сохранить jpg минуя dbimage т.к. не поддерживает. никаких проблем с сами сохранением... у тебя же именно само сохранение и никакого jpg.
(эдак все пересакаюшееся по единому общему термину можно назвать "примерно та же"...)


 
Romul   (2006-06-01 15:00) [27]

Тогда у меня возник еще один вопрос
есть следующий код

 ADODataSet1.Open;
 with ADODataSet1.Fields[0] do
 begin
   if not IsBlob then
     begin
     { Allocate space }
     ds:=DataSize;
     GetMem(Buf, ds);
     try
       if not GetData(Buf) then
          MessageDlg(DisplayName + " is NULL", mtInformation, [mbOK], 0)
       else
         begin
           FS:= TFileStream.Create("c:\1.bmp", fmCreate or fmShareCompat);
           FS.Position:=0;
           FS.WriteBuffer(Buf,ds);
         end;
     finally
       FreeAndNil(fs);
       FreeMem(Buf, ds);
       Image1.Picture.LoadFromFile("c:\1.bmp");
     end;
   end;
 end;

почему может вылетать ошибка Accsess Violation на любом операторе после FS.WriteBuffer(Buf,ds);


 
sniknik ©   (2006-06-01 16:02) [28]

потому, что параметр Buf неверного типа/неправильно передается. вместо записи по нему в выделенную бласть памяти, записывается в него и дальше перетирая все что лежит следом за ним (код например).


 
Romul   (2006-06-01 16:39) [29]

А разве GetMem не выделяет область памяти?


 
Romul   (2006-06-01 17:27) [30]

Вот полный текст процедуры

procedure TForm1.Button4Click(Sender: TObject);
var buf:  PByteArray;
   buf1: array of byte;
   ds: integer;
   i: integer;
   FS: TFileStream;
begin
 ADODataSet1.Open;
 with ADODataSet1.Fields[0] do
 begin
   if not IsBlob then
     begin
     ds:=DataSize;
     SetLength(Buf1, ds);
     GetMem(Buf, ds);
     try
       if not GetData(Buf) then
          MessageDlg(DisplayName + " is NULL", mtInformation, [mbOK], 0)
       else
       begin
         for i:=0 to ds-1 do Buf1[i]:=Buf[i+2];
         FS:= TFileStream.Create("c:\1.bmp", fmCreate or fmShareCompat);
         FS.Position:=0;
         for i:=0 to ds-3 do FS.Write(Buf1[i],1);
       end;
     finally
       SetLength(Buf1,0);
       FS.Free;
       FreeMem(Buf, ds);

     end;
   end;
 end;
 ADODataSet1.Close;
end;

при таком обращении с буфером данные сохраняются,
вся память выделяется, все за собой чистится.
Но Accsess Valation все равно вылазиет....


 
Romul   (2006-06-01 17:47) [31]

Поэксперементировал с полями других типов...
Короче для полей отличных от blob, которые распознаются как VarByte, все работает великолепно... и не возникает ни каких ошибок
У меня уже просто едет крыша над решением вопроса "что такое вечный кайф и как с ним бороться"....

УРАААААААА
НАШЕЛЛЛЛЛЛЛЛ

К датасету не должно быть ничего привязано..... и тогда такая конструкция позволяет записать все из поля блоб в файл


 
Johnmen ©   (2006-06-01 17:50) [32]


> К датасету не должно быть ничего привязано.....


Да ну перестань.


 
sniknik ©   (2006-06-01 17:55) [33]

> А разве GetMem не выделяет область памяти?
она то выделяет, но пишеш то ты, и пишеш в переменную, а не в выделенную память, а в переменной только указатель. все что за ним стирается.

замени PByteArray на array of byte, а GetMem на SetLength. не умееш с
указателями работать.


 
Romul   (2006-06-01 17:56) [34]

хотя нет, погорячился DataSource может быть но вот точно там не должно быть DBNavigator-а иначе вылетает Accsecc Vialation,


 
sniknik ©   (2006-06-01 17:57) [35]

> К датасету не должно быть ничего привязано.....
ну если у тебя привязано чтото у чего есть написаная тобой обработка событий... то не удивительно.


 
Johnmen ©   (2006-06-01 17:58) [36]


> но вот точно там не должно быть DBNavigator-а иначе вылетает
> Accsecc Vialation,


Да ну перестань.


 
Romul   (2006-06-01 18:03) [37]

ни фига, если GetData натравливать на array of byte то вылетает с ошибкой...
при этом еще надо первые 2 байта выкинуть, они там однозначно лишнии


 
Romul   (2006-06-01 18:08) [38]

Я сейчас по поводу этого нехорошешего TypeCast буду говорить много нехороших слов.....
если поле является blob то делфя его понимает как VarByte....
а если оно longblob то и ни каких ухищерений не надо все понимается как блоб.......


 
sniknik ©   (2006-06-01 18:22) [39]

> а если оно longblob то и ни каких ухищерений не надо все понимается как блоб.......
значит тип longblob в mysql этот блоб, а blob это чтото другое. перечитай [20], а TypeCast не трогай он определил уже милиарды раз разные типы, и все правильно, думаеш это был отвлекающий маневр специально тебя запутать?


 
Romul   (2006-06-02 01:18) [40]

У меня возникло такое странное ощущение, что тип поля blob определяется не от реально указанного Datatype в таблице, а от максимального размера поля которое возвращается в датасет.
Короче, получается удаление гланд через задний проход :(
И надо делать как минимум 2 реакции на то, что возвращается...
Если размер в байтах не влезает в 2 байта, то тогда опознается как blob иначе опазнается varchar, и в данных возвращаемых в GetData первые 2 байта лишние. При чем, это касается только полей типа blob (определенных в таблице). По крайней мере, для полей типа VarChar не надо удалять первые 2 байта, там все происходит норамльно.
У меня даже почти возникло желание написать что нить наподобии How to для такой связки D7 - ADO - MySQL ODBC3.51 - MySql, но вот по версиям сервара, что-то нет особого желания проверять.



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2006.08.06;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.012 c
2-1153484990
Itonixxx
2006-07-21 16:29
2006.08.06
Работа со строками


15-1152398312
KilkennyCat
2006-07-09 02:38
2006.08.06
Зачем использовать ИМХО?


2-1152845667
delphi_primat
2006-07-14 06:54
2006.08.06
WinApi на русском


15-1152640667
ArtemESC
2006-07-11 21:57
2006.08.06
Где можно заказать/купить пульт...


1-1150977483
VEZ
2006-06-22 15:58
2006.08.06
Cannot complete a class with incomplete methods implementations.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский