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

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

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

Сообщение Igor_ » 01 дек 2007, 20:13

Проблемы с созданием 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.
..
Подскажите, в чем ошибка?

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Сообщение Tonal » 01 дек 2007, 21:52

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

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

Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

Сообщение Igor_ » 02 дек 2007, 10:17

Большое спасибо.
Заработало.

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

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

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';

Tonal
Сообщения: 104
Зарегистрирован: 30 сен 2007, 13:42

Сообщение Tonal » 02 дек 2007, 14:50

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

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 03 дек 2007, 08:00

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

Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

Сообщение Igor_ » 03 дек 2007, 13:05

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

Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

Сообщение Igor_ » 03 дек 2007, 13:06

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

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 04 дек 2007, 08:52

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

Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

Сообщение Igor_ » 04 дек 2007, 10:35

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

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 04 дек 2007, 11:52

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

Igor_
Сообщения: 6
Зарегистрирован: 01 дек 2007, 20:00

Сообщение Igor_ » 04 дек 2007, 15:31

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

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

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

Спасибо.

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

Ответить