Страница 1 из 1

Проблемы с созданием UDF для Firebird1.0 на C++Builder6

Добавлено: 01 дек 2007, 20:13
Igor_
Проблемы с созданием UDF для Firebird1.0 на C++Builder6.
В общем нужна функция округления до заданного числа знаков.
В стандартной поставке Firebird есть похожая функция в fbudf.dll - round, но
ее регистрация в БД такая:

Код: Выделить всё

declare external function Round
int by descriptor, int by descriptor
returns parameter 2
entry_point 'round' module_name 'fbudf';
А мне нужен параметр double передавать..
Или я чего-то не понял?
Вообще, то задача тривиальная и этот параметр int меня озадачил, но в конце концов решил сам написать UDF.

Текст dll:
============================

Код: Выделить всё

#include <vcl.h>
#include <windows.h>
#include <Math.hpp>
//---------------------------------------------------------------------------
#pragma hdrstop
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    return 1;
}
//---------------------------------------------------------------------------
__declspec(dllexport) double roundTo(double aValue, int digit)
{
    return RoundTo(aValue, digit); 
}
//---------------------------------------------------------------------------
============================
Готовую fbudf.dll ложу в папку UDF сервера

Регистрирую ее в БД так:

Код: Выделить всё

declare external function F_ROUNDTO
  double precision, integer
  returns double precision by value
  entry_point 'roundTo' module_name 'ar_fbUdf';
============================
Когда пытаюсь использовать,

Код: Выделить всё

select f_roundto(12.6, 2) from rdb$database
почему-то она не находится, выдает мне:

Код: Выделить всё

Invalid token.
invalid request BLR at offset 59.
function F_ROUNDTO is not defined.
module name or entrypoint could not be found.
Что самое интересное. У меня есть подобная функция в dll, написанная на Delphi -
тут все нормально проходит. А нужно именно на C++Builder.

В голову пришло, что в С++ сигнатура функции включает и параметы - думал из-за этого не находится функция в dll-ке. Пытался регистрировать следующим образом

Код: Выделить всё

declare external function F_ROUNDTO
  double precision, integer
  returns double precision by value
  entry_point 'roundTo(double,int)' module_name 'ar_fbUdf';
Все равно не помогает, выдается то же самое

Код: Выделить всё

..
function F_ROUNDTO is not defined.
module name or entrypoint could not be found.
..
Подскажите, в чем ошибка?

Добавлено: 01 дек 2007, 21:52
Tonal

Код: Выделить всё

...
extern "C" __declspec(dllexport) double roundTo(double aValue, int digit)
...

Добавлено: 02 дек 2007, 10:17
Igor_
Большое спасибо.
Заработало.

Я так и думал, что что-то с объявлением..

Если не сложно, объясните, пожалуйста, что это мы сделали?

PS. В результате вышло следующее (может кому-то еще поможет, мне такого примера как раз не хватило..)

В dll, кроме extern "C" еще параметры по ссылке передаем

Код: Выделить всё

extern "C" __declspec(dllexport) double roundTo(double& aValue, int& digit)
{
    return RoundTo(aValue, digit);
}
регистрация UDF в БД - добавилось подчеркивание перед именем функции.

Код: Выделить всё

DECLARE EXTERNAL FUNCTION ROUNDTO
    DOUBLE PRECISION,
    INTEGER
    RETURNS DOUBLE PRECISION BY VALUE
    ENTRY_POINT '_roundTo' MODULE_NAME 'ar_fbUdf';

Добавлено: 02 дек 2007, 14:50
Tonal
Igor_ писал(а):Если не сложно, объясните, пожалуйста, что это мы сделали?
Не сложно, но здесь офтопик.
Гугли Name mangling.

Добавлено: 03 дек 2007, 08:00
Dimitry Sibiryakov
Вообще-то в параметр, объявленный BY DESCRIPTOR можно совать все, что угодно. В данном случае "int" никуда не стучит...

Добавлено: 03 дек 2007, 13:05
Igor_
Dimitry Sibiryakov писал(а):Вообще-то в параметр, объявленный BY DESCRIPTOR можно совать все, что угодно. В данном случае "int" никуда не стучит...
Вообще не понял, о чем речь. А понять хочется :)
Напишите, пожалуйста подробнее.

Добавлено: 03 дек 2007, 13:06
Igor_
Tonal писал(а):
Igor_ писал(а):Если не сложно, объясните, пожалуйста, что это мы сделали?
Не сложно, но здесь офтопик.
Гугли Name mangling.
Спасибо, посмотрю

Добавлено: 04 дек 2007, 08:52
Dimitry Sibiryakov
Igor_ писал(а):Напишите, пожалуйста подробнее.
Подробнее некуда. Какое слово непонятно?

Добавлено: 04 дек 2007, 10:35
Igor_
Dimitry Sibiryakov писал(а):Вообще-то в параметр, объявленный BY DESCRIPTOR можно совать все, что угодно. В данном случае "int" никуда не стучит...
Насколько я понял, Вы имели в виду, что в стандартной UDF Round, которая находится в fbudf.dll можно спокойно передавать double параметр и все будет нормально работать?

Добавлено: 04 дек 2007, 11:52
Dimitry Sibiryakov
Передавать - можно. А от нормально работать (насколько я понимаю из кода) - фиг. Но кто мешает перед передачей откастить в NUMERIC?.. Или даже ограничиться этим кастом вместо всей дурной бодяги с UDF...

Добавлено: 04 дек 2007, 15:31
Igor_
Dimitry Sibiryakov писал(а):Передавать - можно. А от нормально работать (насколько я понимаю из кода) - фиг. Но кто мешает перед передачей откастить в NUMERIC?.. Или даже ограничиться этим кастом вместо всей дурной бодяги с UDF...
Супер!
Я как-то об этом не подумал..
Только что попробовал - преобразование к NUMERIC все нормально округляет.

Код: Выделить всё

select cast(12.646 as numeric(15, 2)) from rdb$database
Т.е. UDF, действительно, нафик не нужна..

Спасибо.

Хорошо, конечно, что я с UDF разобрался, в последствии может пригодиться..
А так реально, получается - кучу времени потерял.. :(