Помогите с UDF, пожалуйста!

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

Модератор: kdv

Ответить
KVas
Сообщения: 31
Зарегистрирован: 01 июн 2005, 16:01

Помогите с UDF, пожалуйста!

Сообщение KVas » 03 янв 2006, 13:26

Имеется следующая UDF
{
/* Upper Space Trim*/
/* возвращает входной параметр в верхнем регистре без пробелов */
DECLARE EXTERNAL FUNCTION UST
CSTRING(255)
RETURNS CSTRING(255) FREE_IT
ENTRY_POINT 'UST' MODULE_NAME 'udf_ib'
;
}

function UST(S:PChar): PChar; cdecl; export;
var s_res,s_tmp:string;
i:byte;
begin
s_tmp:=string(S);
for i:=1 to Length(s_tmp) do
if s_tmp<>#32 then s_res:=s_res+s_tmp;
Result:=PChar(AnsiUpperCase(s_res));
end;

Переменная s_alg в ХП описана как VarChar(255). При тестировании:
s_alg=UST('(S_Vh()-S_Id(220)-S_St(230)-S_St(280)) * 0.125');
s_alg=UST(' * 0.125');
s_alg=UST('21 * 0.125888');
получаю, собственно, то что и должен получить:
(S_VH()-S_ID(220)-S_ST(230)-S_ST(280))*0.125
*0.125
21*0.125888
это и понятно и приятно, но следующие две строки
s_alg=UST('(S_Vh()-S_Id(220)-S_St(230)) * 0.125');
s_alg=UST('(S_Vh() - S_Id(220)-S_St( 230) )* 0.135w');
возвращают уже не совсем понятное (одинаковое!) выражение
(S_VH()-S_ID(220)-S_ST(230))*0.10
(S_VH()-S_ID(220)-S_ST(230))*0.10
что бы это значило? Помогите, а!

Сервер FireBird 1.5.2, диалект базы 1, IBExpert ver. 2005.12.21

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 03 янв 2006, 14:42

муть ведь написана. так сложно faq и статью по написанию udf посмотреть, или взять примеры (safeudf)?
Если free_it, то где в функции вызов ib_util_malloc???

KVas
Сообщения: 31
Зарегистрирован: 01 июн 2005, 16:01

Сообщение KVas » 03 янв 2006, 17:56

kdv писал(а):муть ведь написана. так сложно faq и статью по написанию udf посмотреть, или взять примеры (safeudf)?
Если free_it, то где в функции вызов ib_util_malloc???
Позвольте на этот раз не совсем согласиться в том плане, что "...неужели сложно почитать..." Перед тем как отважиться задать вопрос на столь строгом форуме я внял предыдущим наставлениям и теперь статья Кукарцева у меня всегда перед глазами в виде настольной брошюры. Статья по написанию UDF так же прочтена самым внимательным образом. Были попытки использовать все три подхода, описанные в статье, отсюда и неточность с free_it... просто из истории запросов в IBExperte скопировал не ту декларацию. На самом деле после анализа статьи был отложен на потом подход с RETURNS PARAMETER <N>, поскольку такой подход недокументирован и "хранимое в БД объявление функции не совпадает с объявленным, т.е. функци после создания выглядит как обычная функция с возвращаемым в виде строки параметром (а не номером параметра)" (и, кстати, давал точно такие же результаты), подход с FREE_IT также был отложен на потом из-за того, что он "самый худший" по мнению автора статьи, а вот третий подход как нельзя лучше подходит к моей ситуации - имеется ввиду возврат строки, через входной параметр, поскольку длинна возвращаемой строки всегда будет или такой-же как и входная или короче за счет вырезанных пробелов. Ещё раз приношу ивинения за неточность в постановке вопроса - с описанной выше версией UDF (а их было несколько) вариант декларации в UDF имел такой вид:
DECLARE EXTERNAL FUNCTION UST
CSTRING(255)
RETURNS CSTRING(255)
ENTRY_POINT 'UST' MODULE_NAME 'udf_ib'
И в такой ситуации были полученнные такие результаты. Причем если "закоментировать" цикл FOR и в последней строке вместо s_res указать s_tmp, то возвращается вполне ожидаемый результат во всех указанных случаях, а вот когда пробельчики вирезаются, вылазит такая вот бодяга. Ещё раз прошу помочь в решении вопроса...

v6y
Сообщения: 78
Зарегистрирован: 12 мар 2005, 17:45

Сообщение v6y » 03 янв 2006, 22:46

KVas писал(а): ...
Статья по написанию UDF так же прочтена самым внимательным образом...

... а вот третий подход как нельзя лучше подходит к моей ситуации - имеется ввиду возврат строки, через входной параметр, поскольку длинна возвращаемой строки всегда будет или такой-же как и входная или короче за счет вырезанных пробелов.вопроса...
Я из любопытства посмотрел эту статью - чего то сомневаюсь я что вы внимательно ее прочли. Основная идея там в том что возвращается указатель на входной параметр и именно поэтому длина возвращаемой строки не должна превышать длину входной. У вас же возвращается указатель на строку хоть и не превышающую по длине входную, но ссылающуюся хрен знает на какую область памяти. Лень мне сегодня долго объяснить, короче, согласно указанной статье, нужно сделать что-то вроде

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

StrCopy(S,PChar(AnsiUpperCase(s_res));
Result:=S;

KVas
Сообщения: 31
Зарегистрирован: 01 июн 2005, 16:01

Сообщение KVas » 04 янв 2006, 11:07

Вы будете смеяться господа (возможно), но вот такая реализация вышеуказанной функции работает:

function UST(S:PChar): PChar; cdecl; export;
var s_res,s_tmp:string;
i:byte;
begin
// s_tmp:=string(S);
s_tmp:=AnsiUpperCase(string(S));
for i:=1 to Length(s_tmp) do
if s_tmp<>#32 then s_res:=s_res+s_tmp;
// Result:=PChar(AnsiUpperCase(s_res));
Result:=PChar(s_res);
end;

буду признателен за разумное объяснение эдакого, гм, феномена...

v6y
за подсказку спасибо.. похоже, что так и есть.. недопёр :oops: , однако это скорее от недостатка опыта, чем невнимательность, но.. вобщем признаю, не догнал.. и ещё раз спасибо

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 05 янв 2006, 19:50

просто надо следовать примерам (safeudf), понимать разницу между string и pchar, а также отлаживать udf в среде Delphi.

Ответить