udf, Delphi, Interbase

15 отговора 480 прегледа
#1

udf, Delphi, Interbase

Здравейте!
Искам да си напиша едно .dll с няколко ф-ции, които после да използвам като udf-та в interbase. Проблема е с параметрите - входни/изходни, в interbase типа е double precision (double в Delphi), ама в .dll-то като какъв тип да ги обявя - май трябва да ползвам указатели??? Конкретно искам ф-ция която по зададено реално число х да отрязва всичко след к-тата цифра зад запетаята (К и Х са параметри) и да връща резултата....малко help?

Отговор
в отговор на VladoVasilev #2

Re: udf, Delphi, Interbase

Това нещо с типа в DLL-а какъв да бъде не го разбрах... Double си е, нали все пак си го пишеш DLL-а на Делфи?
Ето ти няколко статийки по въпроса, които се надявам, че ще ти свършат добра работа.
[линк]
[линк]
[линк]
[линк]
[линк]
Също така има и някои библиотеки, които можеш да ползваш за разработката на UDF-и. Виж и това:
[линк]
Надявам се "малкото help" да ти е било от полза
Успех с писането!

Отговор
в отговор на andrew_nikoloff #3

Май като за мен трябва малко повече help :)

Явно грешката ми е много тъпа, ама...не иска и не иска - затова реших да попитам тук. Ето unit-a, в който ми е засега единствената ф-ция, която не работи :
"unit uDll;

interface
function RoundUp(num : Double; prec : integer) : Double; cdecl; export;
implementation

Function RoundUp(num : Double; prec : integer) : Double;
var i : integer;
begin
for i := 1 to prec do num := 10*num;
if abs(frac(num)) >= 0.5 then
if num < 0 then num := Trunc(num-1)
else num := Trunc(num+1)
else num := Trunc(num);
for i := 1 to prec do num := num/10;
Result := num;
end;

end."

Добавих си я като udf в interbase по следния начин:
////
DECLARE EXTERNAL FUNCTION ROUNDUP
DOUBLE PRECISION,
INTEGER
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'RoundUp' MODULE_NAME 'uDll'
///
Когато пусна следната заявка:
"select roundup_1(2.34,1) from articleprice;" ми дава
"Unsuccessful execution caused by a system error that precludes
successful execution of subsequent statements.
Access to UDF library "uDll.DLL" is denied by server administrator."
Четох в google, че това може да е от права, от конфигурационния файл на firebird или някаква друга неизвестна грешка. Някой да знае малко повече по въпроса - да не би ф-цията ми да не е правилно написана???

Отговор
в отговор на VladoVasilev #4

Ама дай и малко инфо

Интересува ме:
С каква версия на Firebird си? Каква платформа? Каква файлова система? Каква е стойността на UdfAccess в конфигурационния файл? Къде ти се намира DLL-а?

Отговор
в отговор на andrew_nikoloff #5

Re: Ама дай и малко инфо

A, super - dobre che mi kaza da dam i malko oshte info - poneje imam i INTERBASE SERVER, i FIREBIRD server instalirani, sum kopiral dll-to pri udf-tata na interbase-a, ne na firebird-a....samo che neshto ne smiata kakto triabva, no tova veche sigurno e problem v source-to na samia dll - po-tochno taka kakto sum go napisal vinagi vrushta stoinost 0 - no tova shte go pogledna sega;

Interesno e vse pak, che v firebird.conf imam:
"#UdfAccess = Restrict UDF; d:\work_1\dll;"
i vupreki che v direktoria d:\work_1\dll imam file uDll.dll, pak mi davashe starata greshka....

Отговор
в отговор на VladoVasilev #6

Ами откоментирай го де :-)

Махни '#'-то в началото на реда, че той е символа за коментар

Отговор
в отговор на VladoVasilev #7

Re: Ама дай и малко инфо


library uDll;
uses math;
function roundup(var Num: Double; var Prec: Integer): Double; cdecl;export;
var
LFactor: Double;
begin
LFactor := IntPower(10, Prec);
Result := Round(Num / LFactor) * LFactor;
end;
exports roundup;
{DECLARE EXTERNAL FUNCTION ROUNDUP
DOUBLE PRECISION, INTEGER
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'roundup' MODULE_NAME 'UDll'}
begin
end.




По мотиви от функцията RoundTo в Делфи 7
(а ти май си с 5 :) а там я няма )


RoundTo(1234567, 3) 1234000
RoundTo(1.234, -2) 1.23
RoundTo(1.235, -2) 1.24


Отговор
в отговор на eмил #8

Re: Ама дай и малко инфо

Мерси много, оправи се - проблема беше, че параметрите ми не бяха "var" - незнам все още защо, след като ф-цията си връща стойност (Result := .....), но след като ги сложих да са "var" всичко е ок. Странното е че дори когато единия параметър, който НИКЪДЕ НЕ ПРОМЕНЯМ да не е "var", пак не става - firebird-a направо умира :))

Отговор
в отговор на VladoVasilev #9

Re: Ама дай и малко инфо

Из:
"Как научиться писать UDF для IB Database за 21 мин."
[линк]

"Входные параметры (всегда передаются по ссылке)"
т.е. var :)

И още една много полезна връзка за всеки случай за всякакви
интербейси и огнени птици :)
[линк]

Отговор
в отговор на VladoVasilev #10

Re: udf, Delphi, Interbase

Тъй като гледам, няма нужда нито от dll, нито от udf, ами трябва да се прочете какво прави "CAST"

Отговор
в отговор на TTRex #11

Re: udf, Delphi, Interbase

Пусни си един cast на числата от 0.005 до 10 със стъпка 0.005 и разгледай резултатите. Може да бъдеш неприятно изненадан.

Отговор
в отговор на andrew_nikoloff #12

Re: udf, Delphi, Interbase

Признавам, прочетох невнимателно въпроса, там се иска отрязване, докато cast закръглява. Все пак, аз лично бих написал във въпроса си и нещо като "cast не става, защото...", за да няма двоумение в четящите и да са наясно че и аз съм наясно, и наистина имам пред вид отрязване.
Да, извинявам се.

p.s. andrew_nikoloff, примерът със стъпката обикновено се дава за да се види натрупването на грешките в изчисленията с плаваща точка. Много дълго се чудих това ли имаш пред вид или нещо друго. Наистина, добре е да се пише повечко, за да има яснота

Отговор
в отговор на TTRex #13

Re: udf, Delphi, Interbase

Не, не исках това да кажа. Cast по принцип закръгля, но не можеш да разчиташ на него. На различни машини, различни версии на базата, а може би и в различни ситуации се получават грешки. Например снощи преди да ти отговоря пробвах (не че не ми се е случвало, ама да не взема да изцепя някоя глупост ) и cast от 9.995 ми връщаше 9.99. Обаче на машината в офиса ми връща 10. А сега ми кажи как да разчитам на cast
Лично аз съм си решил въпроса със сторед процедура, защото избягвам udf-ите, но щом човека е решил с udf - нека бъде udf
Успех!

Отговор
в отговор на andrew_nikoloff #14

Re: udf, Delphi, Interbase

Виж ти, не съм обръщал внимание на тези особености.
Пробвах:
select cast(9.995 as numeric(9,2))
from rdb$database
връща нормално, 10.00

обаче ако сложа 9.9949999999999999,
връща 9.99
Значи закръглянето се прави отляво надясно (или от по- високи
разряди към по- ниски); и проблема е свързан с вътрешното
представяне на float.

Изглежда, cast( (MyFloat + 0.0000000001) as Numeric(9,2) )
може да оправи нещата в повечето случаи.

Успех!

Отговор
в отговор на andrew_nikoloff #15

Става все по-яко

Аndrew_nikoloff,
като каза "аз съм си решил въпроса със сторед процедура" каква е реализацията - със cast или? Защото в Interbase-a май няма ф-ция trunc (поне стандартно), нея я има в ib_udf.dll, може би ползваш нея или?

Отговор
в отговор на VladoVasilev #16

Re: Става все по-яко

Не, не е с cast. Сега не мога да си намеря сорсовете, но е направена с преобразуване до varchar и обработката му. Не е особено происводително, но в случая не ми и трябваше.

Отговор