Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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
1-57449
Вампир
2002-03-03 16:40
2002.03.18
Изображение на экране


1-57352
xpyctuk
2002-03-04 15:22
2002.03.18
ISAPI приложение - WebModule, Свойства Request and Response


1-57363
fag2000@ok.ru
2002-03-04 17:00
2002.03.18
Почему нет реакции на сообщение?


1-57342
Канадин Владимир
2002-02-28 12:09
2002.03.18
Достать подменю


14-57505
Жаждущий!
2002-01-31 04:36
2002.03.18
КАК ПРОГАММУ НЕ ИМЕЮЩУУ ФОРМЫ, ОСТАВИТЬ РЕЗИДЕТНОЙ????





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский