5

我正在尝试为 Linux 中的 firebird 创建一些简单的 UDF(使用 GCC 编译的 C 语言)。问题是,当我将“返回机制”设置为“通过引用”时,当我调用该函数时,服务器崩溃了。当它是“按价值”时,没有问题。

以下是我尝试用 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';

我用以下方法调用第二个函数:

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

火鸟服务器崩溃,我得到的唯一错误消息是:

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

AFAIK,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 回答