5

Linux(GCCでコンパイルされたC)でfirebird用の簡単なUDFを作成しようとしています。問題は、「リターンメカニズム」を「参照」に設定すると、関数を呼び出すとサーバーがクラッシュすることです。「値渡し」の場合は問題ありません。

Cで書き込もうとしている関数は次のとおりです。

これは機能します:

double round(double *); 
double round(val)
double *val;
{
    *val = *val * 100;
    *val = (*val>= 0) ? (long)(*val + 0.5) : (long)(*val - 0.5);
    *val = *val / 100;
    return *val;
}

しかし、これは呼び出されるとサーバーをクラッシュさせます:

char * proper_case(str)
char * str;
{
    return str;
}

DDL は次のとおりです。

DECLARE EXTERNAL FUNCTION "ROUND"
    DOUBLE PRECISION
RETURNS DOUBLE PRECISION BY VALUE
ENTRY_POINT 'round' MODULE_NAME 'my_udfs.so';

DECLARE EXTERNAL FUNCTION PROPCASE
    CSTRING(10000)
RETURNS CSTRING(10000) FREE_IT
ENTRY_POINT 'proper_case' MODULE_NAME 'my_udfs.so';

私は2番目の関数を次のように呼び出します:

select propcase('abrakadabra') from rdb$database;

firebird サーバーがクラッシュし、次のエラー メッセージのみが表示されます。

Statement failed, SQLSTATE = -902
Error reading data from the connection.

誰かがアドバイスできますか?どんな助けでも大歓迎です!

提供するのを忘れた唯一の情報は、.so ファイルをコンパイルする方法です (キーはここにある可能性があります)。

gcc -c -O -fpic my_udf.c
ld -G my_udf.o -lm -lc -o my_udf.so
cp my_udf.so /usr/lib/firebird/2.1/UDF/my_udfs.so
4

2 に答える 2

2

私の知る限り、Firebirdは呼び出し後に引数と戻り値の両方を解放しようとします(関数内で何をしているのかわからず、戻り値を として宣言しているFREE_ITため)、戻り値の前にスペースを割り当てる必要がありますそれを返します。呼び出しでメモリを割り当てる必要がib_util_malloc()あるため、次のようになります(コンパイルしようとしてもいませんが、一般的なアイデアが得られるはずです):

char * proper_case(str)
char * str;
{
    char* ret = (char*)ib_util_malloc(strlen(str) + 1);
    strcpy(ret, str); // or run the actual logic here
    return ret;
}

編集:UDF libに組み込まれたFirebirdの例を見つけました:

pChar EXPORT IB_UDF_lower(const char *s)
{
if (!s) return 0;

char* buf = (char *) ib_util_malloc(strlen(s) + 1);
char* p = buf;
while (*s) {
    if (*s >= 'A' && *s <= 'Z') {
        *p++ = *s++ - 'A' + 'a';
    }
    else
        *p++ = *s++;
}
*p = '\0';

return buf;
}
于 2013-03-03T10:43:49.537 に答える
0

ありがとうマーク、あなたは正しかった。コンパイル/リンクに問題があります。

これは正確な答えではありませんが、どうやって問題を解決したかです。

これらのコマンドを使用してUDFをコンパイルしています。

gcc -c -O -fpic my_udf.c
ld -G my_udf.o -lm -lc -o my_udf.so
cp my_udf.so /usr/lib/firebird/2.1/UDF/my_udfs.so

エラーはありませんでした。firebirdサーバーはエラー状態なしでもクラッシュします。そこで、Pythonを開いて、次のことを試しました。

from ctypes import *
libc = CDLL("path/to/my_udf.so")
libc.IB_UDF_lower("abrakadabra")

Pythonは、存在しない関数「ib_util_malloc」に関するエラーをスローします。だから私はそれを「malloc」に置き換えて、すべてがうまくいきました。

何が間違っているのかはまだわかりませんが、GCCでエラーが発生しないため、リンクの問題だと思います。

于 2013-03-06T09:05:46.243 に答える