Форум: "Базы";
Текущий архив: 2002.03.18;
Скачать: [xml.tar.bz2];
ВнизUDF и Interbase Найти похожие ветки
← →
Dimedrol (2002-02-18 15:33) [0]Коллеги, поделитесь опытом плиз.
Узнал я, что можно на Kylix писать *.so-библиотеки
и подшивать их к Interbase.
Попробовал - ок! ;-)
НО, остались некоторые непонятки:
Делаю SO :
library testudf;
uses
SysUtils, Classes;
function Fun1(n:Integer): PChar; cdecl;
var sBuf:string;
i:integer;
begin
if n>=0 then result:="BIGger" else result:="smaller";
end;
exports Fun1;
begin
end.
Подцепляю...
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS CSTRING(32)
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
OK.
Вызываю :
select Fun1(5) from rdb$database;
Вот только почему-то все что я ни передаю -
все возвращает - "smaller"
То есть и "5" и "-3" и "0" это все, типа, меньше нуля...
Что не так ? :-/
← →
Digitman (2002-02-18 16:20) [1]1. IB все параметры в UDF передает по ссылке на временную копию параметра в TLS кодового потока, ассоциированного с клиентским соединением.
2. Для возврата UDF-результата типа PChar необходимо (в общем случае) выделять память под него. По соглашениям IB, для этого необходимо исп-ть мультипоточный менеджер памяти от MSVC : msvcrt.dll
C учетом этих требований твой код должен выглядеть примерно так :
function malloc(Size: Integer): Pointer; cdecl; external "msvcrt.dll";
function Fun1(var n:Integer): PChar;
begin
Result := malloc(8);
if n>=0 then
StrCopy(result, "BIGger")
else
StrCopy(result, "smaller");
end
← →
Digitman (2002-02-18 16:26) [2]P.S. UDF может возвращать в выделенной ей самой памяти (см.malloc) не только строковые результаты, но и любых допустимых в IB типов. При этом важно лишь декларировать в IB-скрипте такие UDF с флагом FREE_IT
← →
Dimedrol (2002-02-18 16:48) [3]А то, что я делаю это под Linux,
не накладывает никаких ограничений\отличий ?
← →
Digitman (2002-02-18 16:53) [4]не буду одназначно утверждать, но - не должно как бы...
почитай док-цию к IB под Linux
← →
Dimedrol (2002-02-18 17:07) [5]Хмммм....
ну допустим...
А как в таком случае мне вернуть из функции
ЧИСЛО ?
Просто число.
ТО есть есть >0 то возвращаем "1"
в противном случае "-1" ?
← →
Digitman (2002-02-18 17:22) [6]под "простым числом" что понимать ? число из "решета Эратосфена" ?
или - Integer, целочисленный знаковый результат, как это принято у программеров ?)
вариантов минимум 2 :
1.
function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
1.
function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
2.
function Fun1(var n:Integer): PInteger;
begin
Result := @n;
if n > 0 then
Result^ := 1
else
Result^ := -1
end;
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
Учти, что в приведенные примерные варианты UDF нельзя передавать неинициализированнй параметр N (имеющий на момент вызова NULL-значение). Иначе неизбежно исключение AV с падением коннекта или всего сервера. В приведенных мной примерах для простоты я не обрабатываю такую ситуацию. В идеале же это необходимо делать обязательно, во избежание генерации в теле UDF любых "непогашенных" исключений, в первую очередь - AV.
← →
Dimedrol (2002-02-18 17:25) [7]Ооо !
Заработало! ;-)
Вот что я написал на Kylix:
uses
SysUtils,
Classes;
const
libcmodulename = "libc.so.6";
Эту фигню скопировал изSysInit.pas
Оттуда же - способ описания функцииMalloc
И далее...
function malloc(Size: LongWord): Pointer; cdecl;
external libcmodulename name "malloc";
function Fun1(var n:Integer): PChar;
begin
Result := malloc(8);
if n>=0 then
StrCopy(result, "BIGger")
else
StrCopy(result, "smaller");
end;
Так, как я понял, чтобы вернуть число,
мне нужно "малочить" например 4 байта для Integer ?!
← →
Digitman (2002-02-18 17:26) [8]вот тебе еще одно решение, неэффективное в данном контексте, но, тем не менее, имеющее "право на жизнь" :
function Fun1(var n:Integer): PInteger;
begin
Result := malloc(sizeof(integer));
if n > 0 then
Result^ := 1
else
Result^ := -1
end;
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer FREE_IT
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
← →
Digitman (2002-02-18 17:29) [9]совершенно необязательно "маллочить" в каждом случае : это зависит от невозможности вернуть результат иным способом, без явного выделения памяти под него
← →
Digitman (2002-02-18 17:37) [10]а способов вернуть результат из UDF в IB - просто куча ) просто в каждом конкретном случае нужно полное понимание механизма передачи конкретных параметров и приема результата
← →
Dimedrol (2002-02-18 17:40) [11]Такс... ;-) Результаты тестирования :
function Fun1(var n:Integer): Integer;
begin
if n > 0 then
Result := 1
else
Result := -1
end;
Подшитая так :
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
или так :
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
не пашет. ;-(
Все время -Result := 1
Пробую дальше...
← →
Dimedrol (2002-02-18 17:51) [12]Ну вот... работает эта :
function Fun1(var n:Integer): PInteger;
begin
Result := @n;
if n > 0 then
Result^ := 1
else
Result^ := -1
end;
Описанная как :
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
Еще 2 небольших вопросика остались...
1. Почему в описании функции
нужно писать именно -( var n:Integer) ?
Разве нельзя просто(n:Integer)
?
2. И зачем в начале ф-ции мы делаемResult := @n;
Вроде ф-ция и так поинтер (): PInteger;
)
Зачем еще это ? 8-\
← →
Digitman (2002-02-18 18:22) [13]Вариант в
Dimedrol © (18.02.02 17:40)
описанный как
DECLARE EXTERNAL FUNCTION Fun1
Integer
RETURNS Integer BY VALUE
ENTRY_POINT "Fun1" MODULE_NAME "libtestudf";
должен работать однозначно !
>>1. Почему в описании функции
нужно писать именно - (var n:Integer) ?
Разве нельзя просто (n:Integer) ?
Нельзя. var = по ссылке.
то, что и передает IB в реальности.
и ты в этом убедился на одном из работающих у тебя примеров
>>2. И зачем в начале ф-ции мы делаем Result := @n;
Вроде ф-ция и так поинтер (): PInteger;)
Зачем еще это ? 8-\
IB выделил врем.память под параметр N, записал туда значение и передал адрес этого параметра тебе в UDF. После приема результата работы UDF он уничтожит этот временный параметр, не контролируя его содержимое. Но ! Поскольку ты передаешь рез-т по ссылке, указывая IB адрес, где рез-т хранится, IB возьмет его по указ.адресу, прежде чем уничтожит свои параметры. А указ.адрес совпадает (Result:= @N !!) с адресом одного из параметров - и ничто не мешает воспользоваться этим фактом ! Все корректно , все довольны, лишних операций с менеджером памяти удается избежать : IB дал тебе врем.буфер со знач.параметра и ответственен за уничтожение буфера после завершения вызова UDF, ты же воспользовался им (буфером) не только для получения зн-я параметра, но и для возврата рез-та через этот буфер !
← →
Dimedrol (2002-02-18 18:46) [14]Мда...
К стати, если передавать строку внутрь,
тоVar
ставить не нужно.
Только вот сейчас проверил.
Наверное потому, что при передачеPchar
как параметра мы и так передаем ссылку.
Да ?!
← →
Digitman (2002-02-18 18:47) [15]Да. PChar есть указатель, а указатель - это и есть ссылка
← →
Dimedrol (2002-02-18 18:50) [16]Ну что-ж...
БОЛЬШОЕ спасибо за помошь !
Ты мне очень помог сегодня ! 8-)
← →
Digitman (2002-02-18 18:51) [17]не за что)
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2002.03.18;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.005 c