powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Дополнительная информация при ошибке в UDF
52 сообщений из 52, показаны все 3 страниц
Дополнительная информация при ошибке в UDF
    #39134020
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сегодня приключилась вот такая ситуация:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
BADGER (Server)	Tue Dec 22 10:20:02 2015
	The user defined function: 	FORMAT_DATE
	   referencing entrypoint: 	FormatDate                     
	                in module: 	gm_udf
	caused the fatal exception: Access violation.
		The code attempted to access a virtual
		address without privilege to do so.
	This exception will cause the Firebird server
	to terminate abnormally.


BADGER (Server)	Tue Dec 22 10:20:02 2015
	Shutting down the server with 48 active connection(s) to 2 database(s), 0 active service(s)

Вопрос разработчикам: можно ли расширить эти сообщения, чтобы в первом случае сообщалось, под каким пользователем выполнялся запрос с этой UDF и в какой базе, а во втором случае, какие именно базы были закрыты.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134103
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxпод каким пользователем выполнялся запрос с этой UDF и в какой базе, а во втором случае, какие именно базы были закрыты.
Кривая udf завалит любой сервер.

П.С. Ставлю рубль на то, что "formatdate" просто написана криво, потому что сервер вряд-ли дает ей кривые данные...
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134111
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

Сервер в лице какого-то пользователя (разработчика) передал туда кривые данные. Я хочу знать, кто это был, чтобы выяснить, что там такое было, и на какой базе.
P.S. С ошибкой в UDF, конечно же, разберемся.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134115
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxСервер в лице какого-то пользователя (разработчика) передал туда кривые данные.
Давай рассмотрим с другой стороны: что туда можно передать кривого? Пустую строку?
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
function DateTimeToChar(var IBDateTime: TIBDateTime; sz: PAnsiChar): PAnsiChar; cdecl; export;
var d: TDateTime;
    u: UTF8String;
    fs: TFormatSettings;
begin
    fs := TFormatSettings.Create;
    with IBDateTime do
        d := Days - IBDateDelta + MSec10 / MSecsPerDay10;
    u := FormatDateTime(UTF8String(sz), d, fs);
    Result := ib_util_malloc(Length(u)+1);
    StrCopy(Result, PAnsiChar(u));
end;


Дак и на выходе будет пустая строка.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134162
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax, к сожалению, чтобы udf могла автоматически (без явной передачи через аргументы) получать хоть какую-то информацию от сервера, надо расширять функционал ib_util.dll. Иначе - только через аргументы функции.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134166
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

Камрад, ты чего оффтопишь? Какая разница, что там в UDF? Это может быть абсолютно любая функция, в том числе состоящая из строки raise Exception.Create. Я спрашиваю про расширение диагностики от сервера, а не про то, как написать функцию, в которой не будет необработанных исключений.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134168
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorCyberMax, к сожалению, чтобы udf могла автоматически (без явной передачи через аргументы) получать хоть какую-то информацию от сервера, надо расширять функционал ib_util.dll. Иначе - только через аргументы функции.
Сообщение в логе формирует сервер в момент падения. Вопрос: при чем тут передача информации от сервера в UDF?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134172
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

в UDR (FB 3) можно получить любую инфу от сервера без проблем. Но их надо научится готовить. Это немного сложнее чем написать UDF.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134175
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax,

не факт что в момент падения можно вытащить информацию о пользователе который его вызвал
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134178
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax, если udf функция может поймать исключение через try/catch блок и обработать, то достаточно получить информацию о контексте транзакции и сохранить необходимую информацию в журнал событий. Вопрос только в том, как получить информацию о контексте транзакции.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134179
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов ДенисDBConstructor, в UDR (FB 3) можно получить любую инфу от сервера без проблем. Но их надо научится готовить. Это немного сложнее чем написать UDF.
Обнадёживающе.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134182
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorCyberMax, если udf функция может поймать исключение через try/catch блок и обработать, то достаточно получить информацию о контексте транзакции и сохранить необходимую информацию в журнал событий. Вопрос только в том, как получить информацию о контексте транзакции.
Какой еще журнал событий? Какой контекст транзакции? Ты тычешь пальцем в небо.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134202
Зимаргл
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
>fatal exception: Access violation.

Гарантированно только дамп можно получить, и из него выколупывать.

Кибермах 5й год сногается с gm_udf, судя по форуму.

P.S. Весьма плохая идея совать внутрь сервера (любого процесса) код от другого компилятора.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134208
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxКакой еще журнал событий?
Любой. В таком варианте хоть на syslogd отправляй - без разницы.
Но было бы идеально, если бы ib_util предоставляла возможность записи в log файл сервера Firebird.

CyberMaxКакой контекст транзакции?
Идентификатор пользователя, идентификатор транзакции и т.д.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134212
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЗимарглP.S. Весьма плохая идея совать внутрь сервера (любого процесса) код от другого компилятора.
Интересное мнение... Обоснуй.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134226
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorЗимарглP.S. Весьма плохая идея совать внутрь сервера (любого процесса) код от другого компилятора.
Интересное мнение... Обоснуй.
"У меня не получилось". (с)
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134231
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЗимарглГарантированно только дамп можно получить, и из него выколупывать.
Не надо никакого дампа.

ЗимарглКибермах 5й год сногается с gm_udf, судя по форуму.
Дык. Сам пишу - сам сношаюсь же.

ЗимарглP.S. Весьма плохая идея совать внутрь сервера (любого процесса) код от другого компилятора.
Какого другого? dll состоит из машинного кода, который все равно, чем и как сформирован.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134234
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

Я тебя умоляю, не пиши в эту тему больше.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134240
MaratIsk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
фигней занимаетесь, господа )))
вот сделать obj client для компиляции в ехе было бы классно
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134256
Зимаргл
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
CyberMaxЗимарглP.S. Весьма плохая идея совать внутрь сервера (любого процесса) код от другого компилятора.
Какого другого? dll состоит из машинного кода, который все равно, чем и как сформирован.
Судя по статистике, многие не понимают промежуточные этапы, что именно "отсебя" добавляет компилятор в машинный код. Не учитывают ньюансы и в итоге подобные проблемы. А ньюансов много.

Была статья на stackoveflow, Но сходу повторно не нашел.

Вкратце, что по разному обрабатывается - классы, стек, потоки, исключения, динамическая память. Наверняка что то спросонья еще забыл.

На этом же форуме много раз писали правильную вещь - избавляйтесь от UDF.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134260
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorCyberMaxКакой контекст транзакции?
Идентификатор пользователя, идентификатор транзакции и т.д.

никто не будет это делать для UDF. UDF имеют множество ограничений и на данный момент это считается Legacy внешними функциями. В UDR это уже есть. На Delphi их тоже можно писать. Сейчас как раз с этим разбираюсь. Даже кое-что удалось сделать.

Кстати я сомневаюсь что ты сможешь перехватить Access violation в коде UDF
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134269
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов ДенисКстати я сомневаюсь что ты сможешь перехватить Access violation в коде UDF
Т.е. обращение по нулевому указателю я могу поймать в try блоке, а "Access violation" нет?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134288
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов ДенисКстати я сомневаюсь что ты сможешь перехватить Access violation в коде UDF
Можно. Это обычное исключение.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134296
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

а где гарантия что Access violation произошёл внутри UDF, а не в момент освобождения выделенной в ней памяти движком FB? Хотя текст ошибки вроде указывает на это.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134304
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис,

Денис, чего ты за AV зацепился? FB падает при любом необработанном исключении в udf.

С другой стороны, кто-нибудь может сказать, зачем FB вообще падает? При вызове UDF достаточно же сделать try/catch, не?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134309
Мимопроходящий
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Hello, Cybermax!
You wrote on 22 декабря 2015 г. 12:04:33:

Cybermax> С другой стороны, кто-нибудь может сказать, зачем FB вообще падает?
> При вызове UDF достаточно же сделать try/catch, не?дык он и делает.
об чём тебе и сообщает в логе.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134318
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax,

дельфийские исключения движком FB не перехватываются. В UDR кстати это можно. Я чуть позже покажу как
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134337
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мимопроходящий, Симонов Денис,

Тогда я не совсем понимаю механику этой ситуации. Движок вызывает UDF через обычный вызов процедуры в DLL. Если там происходит дельфийское исключение, то ...?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134354
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax,

по уму возникшее исключение должно сформировать статус вектор и кинуть ошибку в виде обычной ошибки которая генерируется подобно PSQL оператору EXCEPTION. Т.е. ошибка просто должна высветится у клиента без завершения работы сервера. В UDF статус вектор в который можно засунуть ошибку отсутствует. Чего там делает при этом FB я не знаю, но вероятно просто кидает bugcheck. Появятся источники света может и расскажут.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134360
pastor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxМимопроходящий, Симонов Денис,

Тогда я не совсем понимаю механику этой ситуации. Движок вызывает UDF через обычный вызов процедуры в DLL. Если там происходит дельфийское исключение, то ...?

А оттуда приходит: "нагажено в общую память неизвестно куда и непонятно сколько. выяснили только вот счас и чиста случайно."
Что делает нормальный сервер в ситуации когда ему нагадили в душу? Умывает руки.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134377
Фотография CyberMax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
pastor,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
SVN (Server)	Tue Dec 22 19:38:15 2015
	The user defined function: 	NAME_OF_PERIOD
	   referencing entrypoint: 	NameOfPeriod                   
	                in module: 	gm_udf
	caused the fatal exception: An exception occurred that does
		not have a description.  Exception number EEDFADE.
	This exception will cause the Firebird server
	to terminate abnormally.


SVN (Server)	Tue Dec 22 19:38:15 2015
	Shutting down the server with 1 active connection(s) to 1 database(s), 0 active service(s)


Это выполнился код:
Код: pascal
1.
2.
3.
4.
function NameOfPeriod(var APeriod: Integer): PAnsiChar; cdecl; export;
begin
  raise EDivByZero.Create('DivZero');
end;


Тоже память загажена?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134388
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax,

да. Эксепшн созданный в Delphi не может быть обработан. Кроме того, освободить память которая была выделена в момент создания исключения EDivByZero.Create('DivZero') FB тоже не может.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134422
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMax,

dll может быть создана любым компилятором. ФБ скомпилирован на C++. Как обрабатывать исключения, возникающие в dll, написанные неизвестно на чем - ... никак.

Об этом Харрисон уже давно говорила - при реализации udf было два варианта. либо тупо давать грузить функции из .so, без всякого контроля, но зато чтобы быстро работало, или обрамлять функции тучей проверок, т.е. чтобы медленно, но надежно.
Решили забить болт, и грузить так.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134462
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов ДенисDBConstructor,
а где гарантия что Access violation произошёл внутри UDF, а не в момент освобождения выделенной в ней памяти движком FB? Хотя текст ошибки вроде указывает на это.
Получить в UDF исключение Access Violation, отстреленное Firebird'ом невозможно в принципе. Если ты заглянешь в таблицу экспорта ib_util.dll, то обнаружишь, что там нет функции освобождения общей памяти, т.к. функция ib_util_malloc используется исключительно для выделения памяти под возвращаемый из UDF функции результат и эта память освобождается уже самим сервером после того, как произошел выход из UDF функции и результат возвращен.
Если функции UDF нужна "кучная" память для работы, то она вправе задействовать для этого менеджер памяти самой dll через стандартные Си функции (std::malloc/realloc/free) или операторами C++ (new/delete). Естественно, что все выстреливаемые при этом исключения функция способна обработать самостоятельно в try блоке (сама спровоцировала, сама обработала).
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134469
hvlad
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Любые исключения, использующие стандартные механизмы ОС, можно перехватывать и обрабатывать.
Это раз.

Дельфи использует стандартный механизм и свой собственный код исключения.
У MSVC тоже есть свой код для исключений, как и у любого другого компилятора.
Это два.

Некоторые типы исключений можно обработать гарантированно безопасно и продолжить работу, на остальные непонятно как реагировать.
100500 лет назад было принято решение завершать работу (по возможности - корректным образом) в таких случаях.
За все эти 100500 лет не было предложено ничего лучшего с достойной аргументацией (мне тоже это не нравится, но такова селяви).
Это три.

В самом обработчике исключения контекст (имя БД, юзера и т.п.) - не доступен. Если исключение фатальное (как AV), то exit\abort вызывается из самого обработчика,
т.е. нет возможности выше по стеку добавить контекст в сообщение.
Поэтому та часть сообщения, которая не зависит от исключения (инф-ция об UDF в нашем случае), формируется заранее (до вызова UDF, на самом деле - при загрузке её метаданных).
Можно добавить туда "статическую" инф-цию, не зависящую от контекста конкретного вызова - например имя БД (не уверен, что это будет полезно при анализе причин проблемы).
В принципе, можно перед каждым вызовом UDF добавлять туда и имя юзера, и даже параметры - но кому нужны эти накладные расходы, не востребованные в 99.999% случаях ?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134492
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxС другой стороны, кто-нибудь может сказать, зачем FB вообще падает? При вызове UDF достаточно же сделать try/catch, не?
Потому, что обработка исключений собственными средствами C++ может различаться от компилятора к компилятору и совершенно точно отличается от обработки исключений средствами ОС ( SEH ). Для обработки SEH исключения используются блоки __try/__except/__finally, а не try/catch.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134497
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CyberMaxDBConstructor,
Я тебя умоляю, не пиши в эту тему больше.
Извини, дружище! Я пытался, но не смог удержаться.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134510
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hvladМожно добавить туда "статическую" инф-цию, не зависящую от контекста конкретного вызова - например имя БД (не уверен, что это будет полезно при анализе причин проблемы).
В принципе, можно перед каждым вызовом UDF добавлять туда и имя юзера, и даже параметры - но кому нужны эти накладные расходы, не востребованные в 99.999% случаях ?
Именно поэтому я выше и предлагал несколько расширить функционал ib_util.dll, что никак не скажется на legacy, но позволит UDF функции дополнительно дергать из FB информацию для диагностики.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134524
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorЯ пытался, но не смог удержаться.
почти все твои ответы в этом топике не в кассу, за исключением последних двух, и то, должен заметить, что
- у дельфей, насколько мне известно, нет для dll штатной возможности писать обработчики типа DLL_PROCESS_DETACH и проч, за исключением секции инициализации, которая будет вызываться при загрузке dll.
- даже если по исключению в udf пытаться выгрузить dll и загрузить опять (чтобы освободить память, и т.д.), все равно неизвестно, в какой момент вызвалось исключение, и насколько корректным получится reload.

В общем, все рассуждения про менеджеры памяти и проч - вторичны. Кстати, решение "падать" вместе с udf можно считать оправданым, если учитывать, что начинающие пишут в большинстве именно глюкавые функции. Например, люди могут указать не тот тип вызова (stdcall вместо cdecl), при этом функция может работать ГОДАМИ, выдавая еще и в большей части случаев корректный результат :-)
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134528
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructorСимонов ДенисDBConstructor, в UDR (FB 3) можно получить любую инфу от сервера без проблем. Но их надо научится готовить. Это немного сложнее чем написать UDF.
Обнадёживающе.

И другим интересующимся. Небольшой пример на Delphi XE5. Сначала надо скачать вот это https://github.com/asfernandes/fbstuff/archive/master.zip

Потом немного изменить текст примера для того, чтобы посмотреть как можно обрабатывать исключения в UDR. НУ и естественно последний снапшот тройки.


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
{
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Initial Developer of the Original Code is Adriano dos Santos Fernandes.
  * Portions created by the Initial Developer are Copyright (C) 2015 the Initial Developer.
  * All Rights Reserved.
  *
  * Contributor(s):
}

unit UdrGenRows;

interface

uses FbApi;

{
  create procedure gen_rows (
    start_n integer not null,
    end_n integer not null
  ) returns (
    result integer not null
  )
  external name 'udr!gen_rows'
  engine udr;
}

type
  GenRowsInMessage = record
    start: Integer;
    startNull: WordBool;
    end_: Integer;
    endNull: WordBool;
  end;

  GenRowsInMessagePtr = ^GenRowsInMessage;

  GenRowsOutMessage = record
    result: Integer;
    resultNull: WordBool;
  end;

  GenRowsOutMessagePtr = ^GenRowsOutMessage;

  GenRowsResultSet = class(ExternalResultSetImpl)
    procedure dispose(); override;
    function fetch(status: status): Boolean; override;

  public
    inMessage: GenRowsInMessagePtr;
    outMessage: GenRowsOutMessagePtr;
  end;

  GenRowsProcedure = class(ExternalProcedureImpl)
    procedure dispose(); override;

    procedure getCharSet(status: status; context: ExternalContext;
      name: PAnsiChar; nameSize: Cardinal); override;

    function open(status: status; context: ExternalContext; inMsg: Pointer;
      outMsg: Pointer): ExternalResultSet; override;
  end;

  GenRowsFactory = class(UdrProcedureFactoryImpl)
    procedure dispose(); override;

    procedure setup(status: status; context: ExternalContext;
      metadata: RoutineMetadata; inBuilder: MetadataBuilder;
      outBuilder: MetadataBuilder); override;

    function newItem(status: status; context: ExternalContext;
      metadata: RoutineMetadata): ExternalProcedure; override;
  end;

implementation

uses System.SysUtils;

procedure GenRowsResultSet.dispose();
begin
  destroy;
end;

function GenRowsResultSet.fetch(status: status): Boolean;
begin
  try
    if (outMessage.result >= inMessage.end_) then
      result := false
    else
    begin
      outMessage.result := outMessage.result + 1;
      result := true;
    end;
  except
    on E: Exception do
      FbException.catchException(status, E);
  end;
end;

procedure GenRowsProcedure.dispose();
begin
  destroy;
end;

procedure GenRowsProcedure.getCharSet(status: status; context: ExternalContext;
  name: PAnsiChar; nameSize: Cardinal);
begin
end;

function GenRowsProcedure.open(status: status; context: ExternalContext;
  inMsg: Pointer; outMsg: Pointer): ExternalResultSet;
var
  Ret: GenRowsResultSet;
begin
  Ret := GenRowsResultSet.create();
  try
    Ret.inMessage := inMsg;
    Ret.outMessage := outMsg;

    // Это будет передано на клиента и обработано
    if Ret.inMessage.start > Ret.inMessage.end_ then
      raise Exception.create('start_n > end_n');

    Ret.outMessage.resultNull := false;
    Ret.outMessage.result := Ret.inMessage.start - 1;
  except
    on E: Exception do
      FbException.catchException(status, E);
  end;
  result := Ret;
end;

procedure GenRowsFactory.dispose();
begin
  destroy;
end;

procedure GenRowsFactory.setup(status: status; context: ExternalContext;
  metadata: RoutineMetadata; inBuilder: MetadataBuilder;
  outBuilder: MetadataBuilder);
begin
end;

function GenRowsFactory.newItem(status: status; context: ExternalContext;
  metadata: RoutineMetadata): ExternalProcedure;
begin
  result := GenRowsProcedure.create;
end;

end.




Ну и сравнить результаты двух запросов

Код: sql
1.
2.
3.
4.
5.
select *
from gen_rows(1000, 100)

select *
from gen_rows(1, 100)
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134544
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kdv- у дельфей, насколько мне известно, нет для dll штатной возможности писать обработчики типа DLL_PROCESS_DETACH и проч, за исключением секции инициализации, которая будет вызываться при загрузке dll.
Сдается мне, что Firebird это делает только при завершении процесса сервера, а посему, выделенная, но не освобожденная DLL'ью память не имеет значения и будет освобождена ОС.

kdv- даже если по исключению в udf пытаться выгрузить dll и загрузить опять (чтобы освободить память, и т.д.), все равно неизвестно, в какой момент вызвалось исключение, и насколько корректным получится reload.
А вот это, ИМХО, ни к чему. Лучше откатить транзакцию по какому-нибудь PSQL исключению.

kdvВ общем, все рассуждения про менеджеры памяти и проч - вторичны. Кстати, решение "падать" вместе с udf можно считать оправданым, если учитывать, что начинающие пишут в большинстве именно глюкавые функции.
Спорно...

kdvНапример, люди могут указать не тот тип вызова (stdcall вместо cdecl), при этом функция может работать ГОДАМИ, выдавая еще и в большей части случаев корректный результат :-)
Кстати, очень ценное замечание! Далеко не во всех статьях о создании UDF для Firebird об этом написано. Сам когда-то прошелся по этим же граблям. :)
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134613
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Симонов Денис, я правильно понимаю, что в UDR, в качестве API используется vtable заранее известного класса?
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134652
Зимаргл
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
DBConstructorkdvНапример, люди могут указать не тот тип вызова (stdcall вместо cdecl), при этом функция может работать ГОДАМИ, выдавая еще и в большей части случаев корректный результат :-)
Кстати, очень ценное замечание! Далеко не во всех статьях о создании UDF для Firebird об этом написано. Сам когда-то прошелся по этим же граблям. :)
Ценное, только неверное для 32бит =)
При cdecl стек очищает вызывающая функция,а при sdcall наоборот. Обязано сдохнуть при первом же вызове.

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

Последний пример Симонова для FB3 интересно как себя поведет при AV (где тут главный ломатель? =).

И для полноты картины пара деталей
-для Linux AV обрабатываются совсем по другому.
-есть различия в 32- и 64-бит реализациях
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134683
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

в качестве API используется vtable. Формируется оно с помощью idl для конкретного языка.

ЗимарглПоследний пример Симонова для FB3 интересно как себя поведет при AV (где тут главный ломатель? =).

Я хз. Если не ломать собственные указатели status, context, metadata и т.д., то может и нормально, хотя не факт.

Тут самое сложно это описать входные и выходные сообщения. В C++ варианте есть пример через буфер, от которого смещение берётся.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134698
Фотография Симонов Денис
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Зимаргл
Последний пример Симонова для FB3 интересно как себя поведет при AV (где тут главный ломатель? =).

И для полноты картины пара деталей
-для Linux AV обрабатываются совсем по другому.
-есть различия в 32- и 64-бит реализациях


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
...
function GenRowsProcedure.open(status: status; context: ExternalContext;
  inMsg: Pointer; outMsg: Pointer): ExternalResultSet;
var
  Ret: GenRowsResultSet;
begin
  Ret := GenRowsResultSet.create();
  try
    Ret.inMessage := inMsg;
    Ret.outMessage := outMsg;

    Ret := nil;

    Ret.outMessage.resultNull := false;
    Ret.outMessage.result := Ret.inMessage.start - 1;
  except
    on E: Exception do
      FbException.catchException(status, E);
  end;
  result := Ret;
end;
...



Код: plaintext
1.
2.
Unsuccessful execution caused by system error that does not preclude successful execution of subsequent statements.
Access violation at address 000000000A5CA806 in module 'udr64.DLL'. Read of address 0000000000000018.
At procedure 'GEN_ROWS'.

FB не упал
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134710
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЗимарглЦенное, только неверное для 32бит =)
При cdecl стек очищает вызывающая функция,а при sdcall наоборот. Обязано сдохнуть при первом же вызове.
Вот только причем тут различия в реализациях соглашений вызовов, если вызов udf функций Firebird описан именно как cdecl, а не stdcall? Если бы для вызова udf было принято соглашение stdcall и функции в реализации имели бы stdcall, то и в этом случае всё бы работало. Совершенно очевидно, что какое соглашение принято, такое и должно использоваться.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134723
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

я не понял твой коммент. Ясное дело, что Зимаргл указывает на разницу, почему и пишет, что при неправильной (не той) декларации "должно сдохнуть при первом вызове". Однако, я писал, что неправильная декларация все же иногда работает. Вот пример, и в этом форуме такое было не раз:

http://www.sql.ru/forum/1011000/perenos-udf-s-firebird-2-0-na-2-5?hl=stdcall
"Есть udf, которые работали на FB1, FB2."
"При переносе на FB2.5 библиотека почему-то перестает работать."


еще бывает, что "перестало работать" - при смене ОС (или версии, или 32бит на 64бит), при смене компа, и т.д.
Где-то даже разбирали, почему stdcall в udf прикидывается, что работает, и почему иногда не падает, а возвращает мусор.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134824
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kdvDBConstructor,
я не понял твой коммент. Ясное дело, что Зимаргл указывает на разницу, почему и пишет, что при неправильной (не той) декларации "должно сдохнуть при первом вызове". Однако, я писал, что неправильная декларация все же иногда работает. Вот пример, и в этом форуме такое было не раз:
Должно сдохнуть, но не обязано. Всё очень сильно зависит от того, какие операции были последними над регистрами edx:eax, так как cdecl возвращает значение именно через эти регистры (либо в eax адрес на результат в стеке), а stdcall помещает результат внутрь кадра стека вызывающей программы, получив на него адрес последним неявным параметром в кадре переданных параметров.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39134841
Фотография kdv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DBConstructor,

а, ну тогда консенсус.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39136700
Фотография Tonal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЗимарглИ для полноты картины пара деталей
-для Linux AV обрабатываются совсем по другому.
-есть различия в 32- и 64-бит реализациях
И для совсем полной полноты компилятор С++ MinGw не использует SEH в исключениях бо коллизии с патентами от M$.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39136746
Фотография Tonal
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Детальное описание устройства исключений:
http://habrahabr.ru/post/208006/
http://habrahabr.ru/post/267771/

GCC/SJLJ и GCC/DW2 - это для linux и mingw .
MS VC+ + - SEH - соответственно для остальных виндовых компиляторов.

FPC скорее всего использует какой-то вариант из GCC .
Delphi - SEH .

Для Винды можно делать кросскомпиляторную раскрутку исключения (исключая mingw ), т. к. структура фреймов поддерживается на уровне ОС.
Правда при переходе из кода одного компилятора в другой теряется информация о типе исключения и все связанные с ним данные. Так же, возможны потери памяти и других ресурсов, если к объекту исключения что-то прицеплено. :)

Для Linux кросскомпиляторная раскрутка не делается.
...
Рейтинг: 0 / 0
Дополнительная информация при ошибке в UDF
    #39136776
DBConstructor
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Tonal, для тотальной полноты: SEH не поддерживается только mainline gnu компилятором 32-битных образов (хотя исходный код для поддержки SEH в gcc давно существует) и причина патенты не M$, а Borland (M$ лицензировали SEH у Borland).
К тому же, есть обходные решения :
...
Рейтинг: 0 / 0
52 сообщений из 52, показаны все 3 страниц
Форумы / Firebird, InterBase [игнор отключен] [закрыт для гостей] / Дополнительная информация при ошибке в UDF
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]