2013-03-03 10 views
5

Próbuję utworzyć prosty UDF dla firebirda w Linuksie (w C skompilowany z GCC). Problem polega na tym, że gdy ustawię "Mechanizm powrotny" na "odniesienie", to po wywołaniu funkcji serwer ulega awarii. Gdy jest "według wartości", nie ma problemu.UDF Firebirda w Linuksie powoduje awarię serwera po ustawieniu na powrót przez odniesienie

Oto funkcje Staram się pisać w C:

Ten działa:

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

Ale ten ulega awarii serwera, gdy o nazwie:

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

Oto DDLs :

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

Wzywam Drugą funkcją z:

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

Firebird awarii serwera, a jedynie komunikat o błędzie mam to:

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

Może ktoś doradzić? Każda pomoc zostanie doceniona!

Jedynym informacji zapomniałem dostarczenie jest droga ja kompilacji plik .so (może być kluczem jest tutaj):

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 
+0

Proponuję sprawdzić Rozdział 6 Interbase 6.0 Przewodnik dla programistów (dostępny na http://www.firebirdsql.org/en/reference-manuals/), jeszcze nie napisałem UDF, ale myślę, że przydzielasz pamięć w niewłaściwy sposób. –

+0

Spojrzenie na kod niektórych UDF dostarczanych z Firebirdem może być również pomocne: http://svn.code.sf.net/p/firebird/code/firebird/trunk/src/extlib/ib_udf.cpp –

+0

@MarkRotteveel - Skopiowałem następujące funkcje z Firebird SVN: pChar EXPORT IB_UDF_lower (const char * s) - a wynik jest taki sam. Jedyną zmianą, którą otrzymałem, jest to, że usunąłem słowo EXPORT, ponieważ GCC go nie rozpoznaje. –

Odpowiedz

2

AFAIK, Firebird będzie próbował uwolnić zarówno argumentu i wartości zwracanej po wywołaniu (ponieważ nie wie, co robisz w funkcji i zadeklarowałeś swoją wartość zwracaną jako FREE_IT), musisz więc przydzielić miejsce na wartość zwracaną przed zwróceniem go. Musisz przydzielić pamięci z ib_util_malloc() rozmowy, tak to będzie wyglądać mniej więcej tak (nawet nie próbował go skompilować, ale powinien dać Ci ogólne pojęcie):

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

EDIT: Znalazłem przykład z Firebird zbudowany w UDF lib:

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; 
} 
+0

Usunięcie FREE_IT z deklaracji funkcji również może to naprawić (w ten konkretny przypadek, w którym zwrócona wartość jest identyczna z jednym z parametrów). –

+0

to też moje odczucia, ale nie mogę znaleźć tej części w dokumentach, która wyraźnie to stwierdza, więc pominąłem to. Poza tym, ponieważ nazwa funkcji oznacza, że ​​wartość zwracana różni się od danych wejściowych, nie będzie ona działać ogólnie. –

+0

@Zdeslav - Właśnie go wypróbowałem - przepraszam, wynik jest taki sam :( –

0

Dziękuję Mark, miałeś rację. Coś jest nie tak z kompilacją/linkowaniem.

To nie jest dokładnie odpowiedź, ale jak udało mi się rozwiązać problem.

Mam kompilacji UDF z tych poleceń:

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 

nie było błędów, awarii serwera Firebird również bez stanie błędu. Więc mam otwarte Python i próbował następujący: rzutów błędu

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

Pythona o nie istniejącej funkcji "ib_util_malloc". Wymieniłem go na "malloc" i wszystko działało dobrze.

Nadal nie wiem, co robię źle, ale ponieważ GCC nie daje mi żadnych błędów, przypuszczam, że jest to problem łączący.

Powiązane problemy