Форум: "Базы";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];
ВнизУстановил Yaffil_877ss. Не работает UDF. Найти похожие ветки
← →
kaif (2004-01-15 17:45) [0]Работал на Yaffil_821ss. Установил Yaffil_877ss.
Перестала вызываться моя функция из UDF.
Ошибка "function FROMAT_DATETIME could not be matched"
При этом "стандартные функции IB" работают.
---------------------
DECLARE EXTERNAL FUNCTION FORMAT_DATETIME
CSTRING(30) CHARACTER SET WIN1251, TIMESTAMP
RETURNS CSTRING(30) CHARACTER SET WIN1251 FREE_IT
ENTRY_POINT "FmtIBDateTime" MODULE_NAME "alg_udf";
эта функция не работает (она моя)
---------------------
DECLARE EXTERNAL FUNCTION strlen
CSTRING(32767)
RETURNS INTEGER BY VALUE
ENTRY_POINT "IB_UDF_strlen" MODULE_NAME "ib_udf";
эта функция работает (она стандартная)
-----------------------
Судя по тексту ошибки, функция не находится по имени.
----------------------------
То, что я нашел в FAQ я не очень понимаю:
Yaffil начиная со сборки 867 компилируется MSVC7. Это означает, что теперь используется сервисная библиотека msvcr7.dll, а не msvcrt.dll как раньше (msvc6). В этой библиотеке есть функция malloc, отвечающая за аллокирование памяти.
Таким образом, если ваши udf содержат фунции с free_it, которые напрямую аллокируют память вызовом функции из msvcrt, или наоборот, делают это правильно через ib_util.dll но от сервера IB или FB, в результате получается что ваша udf использует один менеджер памяти, а сервер - другой. Что и приводит ко всяким проблемам с работоспособностью сервера.
Убедитесь, что ваша функция использует вызов не malloc, а ib_util_malloc, и что ib_util.dll имеет версию Yaffil не ниже 865 сборки (а также что на компьютере нет других ib_util.dll, которые могут быть найдены операционной системой ранее правильной ib_util.dll).
Я как-то работал с MSVC7 и мне кажется, что там имена в dll как-то странно приходилось давать (со знаком подчеркивания или как - не помню). К тому же я понимаю, что мне нужно что-то менять в аллокировании памяти (но это уже видимо другая ошибка, которая пока не проявляется, так как не работает сама функция). Подозреваю, что я вообще должен поменять аллокирование памяти, но как правильно - не знаю. Мой текст функции привожу:
function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD): PChar; cdecl; // free_it
var
Tmp: String;
begin
try
Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value));
GetMem(Result, Length(Tmp)+1);
try
StrCopy(Result, PChar(Tmp));
except
FreeMem(Result);
raise;
end;
except
Result:= nil;
end;
end;
------------
Буду благодарен за любые разъяснения и любую помощь в правильном написании этой функции.
← →
Vlad (2004-01-15 18:27) [1]Проблемы не в реализации функции- однозначно.
Скорее либо библиотеку найти не может, либо Entry Point
Попробуй почитать тут:
http://community.borland.com/article/0,1410,25445,00.html
и тут:
http://www.ibase.ru/v6/ib6faq.htm#udf
← →
jack128 (2004-01-15 18:35) [2]
> Убедитесь, что ваша функция использует вызов не malloc,
> а ib_util_malloc, и что ib_util.dll имеет версию Yaffil
> не ниже 865 сборки (а также что на компьютере нет других
> ib_util.dll, которые могут быть найдены операционной системой
> ранее правильной ib_util.dll).
> GetMem(Result, Length(Tmp)+1);
Как это понимать? ;-)
← →
Desdechado (2004-01-15 18:37) [3]опечатка или нет, но в тексте ошибки FROMAT, а в описании FORMAT
← →
Vlad (2004-01-15 18:38) [4]
> jack128 © (15.01.04 18:35) [2]
А чего тут понимать ? Выделение пямяти под Result, проблема явно не в этом.
← →
Desdechado (2004-01-15 18:40) [5]> Yaffil начиная со сборки 867 компилируется MSVC7
вот это мне не нравится. А общий проект Firebird-Yaffil после объединения на чем лепить будут?
← →
jack128 (2004-01-15 18:44) [6]
> А чего тут понимать ? Выделение пямяти под Result, проблема
> явно не в этом.
внимательно считываемся в цитату кайфа, насчет того какой функцией должна выделяться память под free_it результат.
← →
Vlad (2004-01-15 18:47) [7]
> jack128 © (15.01.04 18:44) [6]
Максимум что может быть, так это ошибка Invalid Pointer Operation при выполнении этой ф-ции, хотя лично я в Yaffil"овских UDF все время GetMem пользовался, проблем еще ни разу не было.
← →
jack128 (2004-01-15 19:06) [8]
> Vlad © (15.01.04 18:47) [7]
> UDF все время GetMem пользовался, проблем еще ни разу не
> было.
То что проблем нету сейчас не означает. что их небудет потом(например в новой версии Delphi). Меня вообще то больше интересует зачем kaif привел эту цитату, если сам не соблюдается данные в ней рекомендации ;-)
← →
Vlad (2004-01-15 19:10) [9]
> jack128 © (15.01.04 19:06) [8]
> То что проблем нету сейчас не означает. что их небудет
> потом(например в новой версии Delphi)
Скорее в новой версии Yaffil.
На самом деле ошибка совершенно не связана с реализацией функции. Судя по тексту ошибки, и первой моей ссылке из [1], до выполнения функции дело вобще не доходит.
← →
jack128 (2004-01-15 19:20) [10]
> Судя по тексту ошибки, функция не находится по имени.
как функция экспортируется? Имена функций в dll - регистрочувствительны.
← →
kaif (2004-01-15 19:28) [11]Дико извиняюсь!!!
Действительно, при деинсталляции прежнего Yaffil у меня удалилась моя dll из каталога UDF. Так как тот инсталлятор я сам писал и заодно включил свою dll в инсталляцию. :(
Так что UDF заработали. Но что касается новой mvcrt это меня озадачило.
2 Desdechado © (15.01.04 18:37) [3]
Ошибка "function FORMAT_DATETIME could not be matched". Я опечатался, набирая текст от руки.
2 jack128 © (15.01.04 19:06) [8]
Я этот FAQ прочитал только сегодня. Я и не знал, что нельзя использовать дельфийский менеджер памяти GetMem. Скорее всего, я с самого начала делал что-то неправильно. Но так как это работало, а утечки ресурсов я не наблюдал, я думал, что действую верно... Видимо, жестоко ошибался.
2 Vlad
Большое спасибо за ссылку!!!!!!!!!!!!
Как правильно аллокировать память для UDF с FREE_IT?
Нужно делать следующим образом - начиная с InterBase 5.0 в комплект сервера входит ib_util.dll содержащая функцию ib_util_malloc. Ее объявления для C и Pascal есть в каталоге include:
ib_util.h - extern void * ib_util_malloc (long);
ib_util.pas - function ib_util_malloc(l: integer): pointer; cdecl; external "ib_util.dll";
Для аллокирования памяти и FREE_IT нужно использовать эту функцию. Поскольку сервер сам освобождает занятый участок памяти, функция для освобождения памяти в этой библиотеке не предусмотрена.
При этом ib_util.dll должна находиться в PATH или рядом с вашей dll UDF. Позаботьтесь о том, чтобы на сервере не было двух или более ib_util.dll от разных серверов. В противном случае возможна некорректная работа сервера, его падение или что еще хуже - повреждение базы данных.
Использование ib_util является 100% переносимым, т.к. эта библиотека является стандартной для Interbase (всех версий выше 5.0), Firebird и Yaffil и поставляется под все платформы.
Если вы сами аллокируете/деаллокируете память внутри UDF (с FREE_IT или без), то можете для этих целей использовать любые функции, в том числе getmem/freemem в Delphi.
Однако последний абзац меня опять озадачил.
Может, кто-то прояснит? Теперь можно использовать GetMem так как я использую, то есть с последующим FREE_IT ?
Я так понимаю, что по логике нельзя... Тогда о чем речь в последнем абзаце?
← →
Vlad (2004-01-15 19:43) [12]
> Я так понимаю, что по логике нельзя... Тогда о чем речь
> в последнем абзаце?
Да фигня всё это. С чего ты взял что GetMem нельзя использовать ?
То что ты прочитал в FAQ означает то, что нельзя использовать ф-цию malloc (вместо нее ib_util_malloc). А GetMem никто не отменял :-)
← →
jack128 (2004-01-15 19:45) [13]
> Теперь можно использовать GetMem так как я использую, то
> есть с последующим FREE_IT ?
> Я так понимаю, что по логике нельзя...
Правильно понимаешь.
> Тогда о чем речь в последнем абзаце?
Речь об этом
> function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD):
> PChar; cdecl; // free_it
> var
> Tmp: String;
> begin
> try
> Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value)); // память под temp аллокирует дельфийский менеджер памяти
> GetMem(Result, Length(Tmp)+1);
> try
> StrCopy(Result, PChar(Tmp));
> except
> FreeMem(Result);
> raise;
> end;
> except
> Result:= nil;
> end;
> end; // Тут он осводождает память из под Temp.
В этом нет ничего странного так как память выделяется/освобождается ПАРНЫМИ функциями.(одним и тем же менаджером памяти)
Поэтому же для free_it результатов память нужно выделять ОБЯЗАТЕЛЬНО c помощью ib_util_malloc, так как сервер осводождает память в помоью парной её функции. То есть выделение/освобождение памяти происходит с помощью одного менаджера памяти.
← →
Vlad (2004-01-15 19:53) [14]
> jack128 © (15.01.04 19:45) [13]
Если память выделяет один менеджер, а освобождает другой, это совершенно не значит что возникнет ошибка.
← →
jack128 (2004-01-15 19:59) [15]
> Если память выделяет один менеджер, а освобождает другой,
> это совершенно не значит что возникнет ошибка
не так мыслишь.
Если память выделяет один менеджер, а освобождает другой, это не значит, что ошибка НЕ возникнет ;-). А так как во внутрености менаджеров мы залесть не можем(или можем, но ВЛО-О-ОМ :-))), то лудше не рисковать.
← →
Vlad (2004-01-15 20:04) [16]
> jack128 © (15.01.04 19:59) [15]
Кстати твои комментарии:
// память под temp аллокирует дельфийский менеджер
// Тут он осводождает память из под Temp.
не совсем верны. Точнее сказать они будут верны если ты сам, собственноручно подключешь в uses менеджер ShareMem.
Без этого, память не будет сама ни выделяться ни освобождаться. А выделяет автор ее ручками (GetMem), освобождает сервер (как показывает практика - успешно). Так что все справедливо.
← →
jack128 (2004-01-15 20:09) [17]
> Vlad © (15.01.04 20:04) [16]
Вообще не понял. Кто ж тогда память выделяет? (под temp)
← →
Vlad (2004-01-15 20:15) [18]
> jack128 © (15.01.04 20:09) [17]
Да, сорри, temp - это string, поэтому Delphi сам выделяет и освобождает память.
Но Temp в данном случае не причем, не она же на сервер передается. Речь идет о переменной Result, а под нее автор ручками выделяет память.
← →
jack128 (2004-01-15 20:19) [19]Ну да. Я привел этот пример, что бы показать, что выделять память под переменную, которая НЕ будет передаваться на сервер можно любым менеджером..
← →
kaif (2004-01-15 20:21) [20]2 jack128 © (15.01.04 19:45) [13]
я правильно тебя понял, что на всякий пожарный мне нужно переписать функцию и вместо GetMem использовать ib_util_malloc ?
Но если это так, то что мне использовать вместо FreeMem?
Или мне вообще выкинуть конструкцию с try .. except ?
А если у меня будут какие-то рискованные вещи и нужно будет использовать try .. except, что мне применять в качестве FreeMem ?
У меня такое ощущение, что народ что-то умалчивает. Или есть еще функция free_it в этой dll и надо именно ее юзать?
← →
Vlad (2004-01-15 20:21) [21]Да, судя по всему ты прав, последний абзац именно это и означает.
Если вы сами аллокируете......
имелось ввиду, что под любые другие переменные (не Result)
← →
Vlad (2004-01-15 20:23) [22]
> что мне использовать вместо FreeMem?
Вместо Free_Mem сервер будет делать FREE_IT сам, если указана данная опция в UDF
← →
Vlad (2004-01-15 20:46) [23]Кстати, для полной ясности решил провести небольшой тест.
Использовал UDF, где аллокировал память под Result с помощью GetMem
На небольших таблицах работает четко, но как только пробую делать апдейт с помощью этой функции на таблице с 4 млн записей, то примерно на втором миллионе выдает ошибку....
Так что вот... jack128 © был прав. Выделять память лучше тем же менеджером, который потом будет освобождать.
← →
kaif (2004-01-15 22:24) [24]2 Vlad © (15.01.04 20:46) [23]
OK. Спасибо большое. Особеннно за эксперимент с GetMem.
Всем спасибо. Век живи - век учись. Пойду исправлять.
← →
kaif (2004-01-15 23:45) [25]В общем, теперь это выглядит так:
function ib_util_malloc(l: integer): pointer; cdecl; external "ib_util.dll";
function FmtIBDateTime(FmtStr: PChar; var Value: TISC_QUAD): PChar; cdecl; // free_it
var
Tmp: String;
begin
Tmp:= FormatDateTime(StrPas(FmtStr), QuadToDate(Value));
Result := ib_util_malloc(Length(Tmp)+1);
StrCopy(Result, PChar(Tmp));
end;
А в декларации функции, соответственно, FREE_IT
И все в таком духе. Работает. Надеюсь, теперь правильно.
Еще раз спасибо всем.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2004.02.06;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.023 c