Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Интерфейс взаимодейстия с базой


Страницы:   1 2

Piter ©   (2006-01-02 23:33:00) 

Нужна организовать для DLL-плагина к программе доступ к SQL-базе. База - Interbase, но это не так важно.

То есть, внутри программы понятно: TDatabase / TQuery - все ясно.

А вот как организовать интерфейс взаимодействия с плагином? Чтобы плагин мог выполнять SQL запросы и получать результаты? Может кто занимался подобным, имеет опыт?

Может что-то типа:

CreateRequest('SQL-выражение') - функция возвращает Handle некоего созданного объекта (ну там ноль в случае неудачи)

Потом всякие:

GetParam(Handle, 'ParamName', AsInteger)

А в конце работы нужно закрыть объект:

CloseRequest(Handle);

Соответственно, в программе Handle это может быть чисто физически просто адрес TQuery. При выполнении запроса CreateRequest создается объект TQuery, Handle возвращается плагину. При CloseRequest объект TQuery уничтожается.

TQuery вроде как потоко-безопасный.

Покритикуйте плиз данную схему и как по другому можно?

В данной схеме меня пока смущает частое создание/уничтожение объекта TQuery - при каждом запросе. С другой стороны, вроде ничего страшного, TDataBase один общий будет, так что по скорости проблем особо не должно быть.


Sergey Masloff   (2006-01-03 18:25:00) [1]

Ты сделай select * from big_table, small_table
получишь m*n записей ;-)))))
только 2 раза большую не множь а то устанешь ждать
Кстати может в новых IBX подняли размеры? Надо будет посмотреть. Я в 2003 году явление наблюдал - у меня начали клиенты стали сообщать об ошибке при одной из операций, в результате очень долгих тестовых мук было установлено что дело в IBQuery (или IBDataSet) и ограничении его внутр. буфера.


Piter   (2006-01-03 18:20:00) [2]

генерировать влом, но потом может потестю :)


Piter   (2006-01-03 18:19:00) [3]

Sergey Masloff   (03.01.06 18:06) [25]
По моим (давним) наблюдениям предел размера буфера порядка 5 Мб.


в этом наверное дело, вся база занимает: 11,2 Mb

Там 2 больших таблицы и несколько мелких (очень мелких). Тестируемая таблица самая большая, но видимо не дотягивает...

Тогда надо таблицу на сотню тысяч записей взять... У меня такой под рукой нету :(


Piter   (2006-01-03 18:17:00) [4]

Sergey Masloff   (03.01.06 18:06) [25]

Last сделал, тестировал на стандартном D7.
Записей в таблице: 17610

Вроде никаких таких тормозов и ошибок памяти.

Единственное что - использовал для тестов Embedded версиб FB, локальную. Но это должно быть пофигу я думаю для TQuery - ему то откуда знать.


Piter   (2006-01-03 18:11:00) [5]

Sergey Masloff   (03.01.06 18:06) [25]

сделал


Sergey Masloff   (2006-01-03 18:06:00) [6]

Piter ©   (03.01.06 17:22) [24]
Last() сделал? ;-)
Если нет то и говорить не о чем. По моим (давним) наблюдениям предел размера буфера порядка 5 Мб.


Piter   (2006-01-03 17:22:00) [7]

Sergey Masloff   (03.01.06 14:11) [22]
Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей


сейчас руки дошли.

Итак, в таблице post всего записей: 17610

При этом запрос:

IBQuery1.SQL.Add('Select * from post');

Выполняется быстро и никаких нехваток памяти.


Piter   (2006-01-03 14:27:00) [8]

Sergey Masloff   (03.01.06 14:11) [22]
Да что угодно. Потеряет плагин твой хендл и все


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

Тоже самое, что процесс в Windows может наоткрывать кучу файлов, насоздовать кучу окон - все будет тормозить, но система ничего с этим поделать не в состоянии - а может прада процессу столько нужно?

Так что тут вопрос такой... В конце концов плагин работает в ВАП моего процесса, поэтому при "умелом" программировании он полюбому сможет убить ядро программы, тут как ни крутись...

Sergey Masloff   (03.01.06 14:11) [22]
Как обычно спросил->данные получил->отвалился


Да, тут согласен, в моем варианте ПЛАГИН должен закрывать TQuery, это как недостаток при неумелом программировании, так и достоинство при умелом.

Sergey Masloff   (03.01.06 14:11) [22]
Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей


хм... сча потестю :)


Sergey Masloff   (2006-01-03 14:11:00) [9]

2) Потому что (IB)Query расходует кучу ресурсов на поддержку двунаправленых курсоров. Так что прочитать все через компоненты без этого оверхеда и завернуть все в строковый буфер врядли сильно медленннее. Кроме того тот же IBQuery упадет с EOutOfMemory гораздо раньше чем пойдет речь о десятках тысяч записей.

>Ведь может быть несколько плагинов, каждый вправе использовать базу >данных...
Как обычно спросил->данные получил->отвалился. И так все хоть 100 штук одновременно

>а что значит плагин отвалится?
Да что угодно. Потеряет плагин твой хендл и все. Вариантов масса - от простых ошибок до умелого применения try except<пусто><end>


Piter   (2006-01-03 14:04:00) [10]

Desdechado ©   (03.01.06 13:50) [18]
ты для каждого плага собираешься свое множество квериков хранить


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

Собственно, с другой стороны - один плагин может вполне обойтись одним своим TQuery.

Sergey Masloff   (03.01.06 13:57) [19]
Тут проблем нет есть свойство StatementType или что-то в этом роде возвращает перечислимое значение


это свойство есть у TQuery?

Тогда не в тему, но странно - а зачем в самом TQuery разделили процедуры Open и ExecSQL?


Piter   (2006-01-03 13:58:00) [11]

Sergey Masloff   (03.01.06 13:46) [17]
1) при чем тут вообще THandle - дельфийский псевдоним для Integer


ну просто ссылки на объекты ядра обычно имеют в Delphi возвращаемый тип YHandle, вот и все. Например: CreateMutex, CreateSemaphore :)

Можно с таким же успехом просто LongWord использовать

Sergey Masloff   (03.01.06 13:46) [17]
2) если запрос вернет несколько тысяч записей ресурсов при использовании T(IB)Query уйдет не меньше а как бы и не больше чем в моем варианте


хм... почему?

В твоем варианте я считаю кучу времени уйдет на формирование ИЗ набора даных текстовых XML строк. А у меня?

Sergey Masloff   (03.01.06 13:46) [17]
Ты собираешься держать тучу открытых запросов еще и с навигацией по ним


а какие еще варианты? Ведь может быть несколько плагинов, каждый вправе использовать базу данных...

Sergey Masloff   (03.01.06 13:46) [17]
Причем если у тебя плагин отвалится то ты об этом никогда не узнаешь и открытый запрос останется навеки


а что значит плагин отвалится? Выгрузится DLL-библиотека из адресного пространства? Сам себя что ли плагин выгрузит?


Sergey Masloff   (2006-01-03 13:57:00) [12]

Piter ©   (03.01.06 13:38) [15]
>хотелось бы универсальной функции: CreateRequest, то есть, которая >принимала бы и SELECT запросы, и INSERT, UPDATE и так далее, >преобразовывая в вызовы нужных методов TQuery: Open или ExecSQL
Тут проблем нет есть свойство StatementType или что-то в этом роде возвращает перечислимое значение с типом выражения нк там INSERT или скажем DDL или DELETE


Desdechado   (2006-01-03 13:50:00) [13]

ты для каждого плага собираешься свое множество квериков хранить (т.е. разделять будешь) или общий пул на всех (а как тогда с "чужими" некорректные операции)?


Sergey Masloff   (2006-01-03 13:46:00) [14]

Нет непонятно.
1) при чем тут вообще THandle - дельфийский псевдоним для Integer
2) если запрос вернет несколько тысяч записей ресурсов при использовании T(IB)Query уйдет не меньше а как бы и не больше чем в моем варианте
3) Ты собираешься держать тучу открытых запросов еще и с навигацией по ним. Причем если у тебя плагин отвалится то ты об этом никогда не узнаешь и открытый запрос останется навеки

Вобщем, идея мертвая. ИМХО. Дерзай может что и получится


Piter   (2006-01-03 13:41:00) [15]

В общем, я так понял мое направление правильное :)
Сергей мыслит бизнес-процессами, поэтому предполагает использование серъезных технологий, а у меня тут не так :)

Думаю, это самое оптимальное - использование TQuery и предоставление доступа к нему как к объекту ядра, то есть плагин просто каждый раз будет передавать Handle и вызывать нужные ему функции по работе с данными.

А в конце вызывается: CloseRequest(Handle) и тогда в ядре программы соответствующий объект TQuery уничатожается...

Если кто что понял - покритикуйте :)


Piter   (2006-01-03 13:38:00) [16]

Возникает пока 1 вопрос по МОЕМУ способу:

хотелось бы универсальной функции: CreateRequest, то есть, которая принимала бы и SELECT запросы, и INSERT, UPDATE и так далее, преобразовывая в вызовы нужных методов TQuery: Open или ExecSQL.


Piter   (2006-01-03 13:32:00) [17]

Sergey Masloff   (03.01.06 13:00) [13]
Тогда какие к фигам Query?


Эх... Сергей!!! Перечитай плиз первые мои два поста!!!

О TQuery я говорил в том смысле - КАК сама работа с базой будет в ядре осуществляться. А плагин то понятное дело ни о каких TQuery и не знает.

Твою идею понял - возвращать весь набор данных в виде аля XML... Но а вдруг запрос вернет тысячи записей??? А если вдруг миллион? На формирование такого списка уйдет безумная куча времени и ресурсов... Мне пока мой способ нравится больще.

Итак, еще раз мой способ.

Это как бы перенос идеи объекта ядра из Windows. То есть, плагин создает объект ядра:

CreateRequest('SQL запрос');

Ему возвращается Handle. Далее используя этот Handle он может оперировать с открытым набором данных, как то:

GetIntegerParam(Handle, 'ParamName'): integer

SetPosition(Handle, spNext): boolean

вместо spNext там: spBack, spFirst, spLast.

В САМОМ же движке это может быть наглядно реализовано, например:

function CreateRequest(SQLRequest: PChar): THandle; stdcall;
var
 query: TQuery
 s: string;
begin
 s := SQLRequest;
 query := SQLManager.CreateQuery;
 if query = nil then
   Result := 0
 else
 begin
   query.SQL.add(s);
   query.Open;
   Result := THandle(Pointer(Query));
 end;

Или типа подобного, я сейчас от руки набросал - но думаю понятно.


Sergey Masloff   (2006-01-03 13:00:00) [18]

Piter ©   (03.01.06 12:51) [12]
>плагин может быть написан и на Delphi, и на C++,
Да я это просмотрел. Тогда какие к фигам Query? Их просто не существует в це бейсики и вообще нигде кроме борланда.
Тогда можно использовать или рекордсеты ADO (но соответственно ADO нужно) или все данные отдавать в raw виде - ну там массив OLE Variants или самому конструировать строку вида

<rowset name = "custom name">
 <row>
   <col kind="myint" name = "field1">field1value</col>
   <col kind="mystr" name = "field2">field2value</col>
   ....
 </row>
 ....
</rowset>

выделять под нее память и отдавать указатель на нее и размер плагину. А там пусть разбирает как хочет


Piter   (2006-01-03 12:51:00) [19]

Sergey Masloff   (03.01.06 8:29) [8]
Естественно все это работает только если клиентские плагины дельфийские или C++Builder овские


так вот ничего естественного!

Сергей, я же писал:

Piter ©   (03.01.06 1:12) [5]
плагин может быть написан и на Delphi, и на C++, на чем угодно, что может вызывать WinApi функции и компилировать библиотеки DLL.


то есть, фактически НИКАКИХ объектов, так как .NET не планируется.

Desdechado ©   (03.01.06 11:30) [11]
Обязательно при передаче хэндлов (если ты хочешь именно по-своему сделать) помни, что компилироваться твоя прога и плагины должны на ИДЕНТИЧНЫХ версиях


да НЕ БУДЕТ плагин знать о том, что Handle - это ссылка на TQuery. Для плагина это как объект ядра программы. Handle можно и не ссылкой на TQuery делать, а рандомно генерить, просто так удобно и обеспечивается уникальность Handle...


Desdechado   (2006-01-03 11:30:00) [20]

Обязательно при передаче хэндлов (если ты хочешь именно по-своему сделать) помни, что компилироваться твоя прога и плагины должны на ИДЕНТИЧНЫХ версиях, ибо описание класса хранится и в EXE, и в DLL. И может (при разных версиях) получиться так, что обращаясь (в EXE) к TQuery.SQL.Text из плагина ты, на самом деле, обратишься к какому-нить другому свойству, расположенному по этому адресу (из-за несоответствия описания таблицы классов).
Часто это выявляется далеконе сразу, ибо положение свойств классов меняется редко, но вполне возможно. И будешь ловить AV и долго гадать, в чем дело...


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо