Обсуждение: Srf function : missing library on PostgreSQL 8.3.6 on Windows?
Hello, I try to use the srf API and I have a link error. When I did : FuncCallContext *funcctx; ... if (SRF_IS_FIRSTCALL()){ funcctx = SRF_FIRSTCALL_INIT(); // If I remove this line, no link error ... } I have this link error : "undefined reference to 'init_MultiFuncCall(FunctionCallInfoData*)'". The init_MultiFuncCal function is in the funcapi.h file, but where is the associated library ? I try all the libraries of PostreSQL, but no success ![]() Any idea ? Thanks. |
Ben Ali Rachid <souliman239@yahoo.fr> writes: > I have this link error : "undefined reference to 'init_MultiFuncCall(FunctionCallInfoData*)'". The fact that the linker knows the argument data type indicates that you're trying to compile your code as C++. Postgres is written in C, not C++. You can try putting extern "C" { ... } around your inclusions of Postgres header files, but you're likely to run into other problems later on. On the whole I'd recommend using plain C for backend functions if you possibly can. regards, tom lane
Thanks for your help. I try "extern C" for the inclusions and everything is OK. But now I have execution error (server crash), but it's another problem that I will try to solve. --- En date de : Ven 20.3.09, Tom Lane <tgl@sss.pgh.pa.us> a écrit :
|
Ben Ali Rachid wrote: > Thanks for your help. I try "extern C" for the inclusions and everything is OK. But now I have execution error (servercrash), but it's another problem that I will try to solve. If you're using C++ you must also: - Ensure that no exceptions propagate outside your code - Declare all hook functions that might be dlopen()ed as extern "C" As Tom Lane pointed out in an earlier thread about this you'll also have problems with Pg's longjmp based error handling skipping past exception-driven cleanup, so you can't rely on RAII and scoped objects. -- Craig Ringer
Craig Ringer wrote : > If you're using C++ you must also: > - Ensure that no exceptions propagate outside your code > - Declare all hook functions that might be dlopen()ed as extern "C" Thanks for your advices but I'm not sure to have understood.. For example, when I try to implement the "normal_rand" function from "/contrib/tablefunc" like below, I have a server crash. /****************** * test.h * ******************/ extern "C" { #include "postgres.h" #include "fmgr.h" #include "funcapi.h" #include "executor/spi.h" #include "lib/stringinfo.h" #include "miscadmin.h" #include "utils/builtins.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include <math.h> } extern "C" __declspec (dllexport) Datum normal_rand(PG_FUNCTION_ARGS); /********************* * test.cpp * *********************/ #include "test.h" PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(normal_rand); Datum normal_rand(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; normal_rand_fctx *fctx; float8 mean; float8 stddev; float8 carry_val; bool use_carry; MemoryContext oldcontext; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* total number of tuples to be returned */ funcctx->max_calls = PG_GETARG_UINT32(0); /* allocate memory for user context */ fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx)); /* * Use fctx to keep track of upper and lower bounds from call to call. * It will also be used to carry over the spare value we get from the * Box-Muller algorithm so that we only actually calculate a new value * every other call. */ fctx->mean = PG_GETARG_FLOAT8(1); fctx->stddev = PG_GETARG_FLOAT8(2); fctx->carry_val = 0; fctx->use_carry = false; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; fctx = (normal_rand_fctx*) funcctx->user_fctx; mean = fctx->mean; stddev = fctx->stddev; carry_val = fctx->carry_val; use_carry = fctx->use_carry; if (call_cntr < max_calls) /* do when there is more left to send */ { float8 result; if (use_carry) { /* reset use_carry and use second value obtained on last pass */ fctx->use_carry = false; result = carry_val; } else { float8 normval_1; float8 normval_2; /* Get the next two normal values */ get_normal_pair(&normval_1, &normval_2); /* use the first */ result = mean + (stddev * normval_1); /* and save the second */ fctx->carry_val = mean + (stddev * normval_2); fctx->use_carry = true; } /* send the result */ SRF_RETURN_NEXT(funcctx, Float8GetDatum(result)); } else /* do when there is no more left */ SRF_RETURN_DONE(funcctx); } /***************** * script * *****************/ CREATE OR REPLACE FUNCTION normal_rand(int4, float8, float8) RETURNS setof float8 AS '$libdir/tablefunc','normal_rand' LANGUAGE C VOLATILE STRICT; In the log file, it indicated that the server stop with an exception (0xC0000005). In the "ntstatus.h", it indicated that this exception 0xC0000005 means ACCESS VIOLATION. I don't know what causes this exception. It's also a problem with some missing " extern 'C' " ? Or is it a null pointer problem ? Tom Lane wrote : > On the whole I'd recommend using plain C for backend functions if you possibly can. Unfortunately, I must use cpp because I must translate an temporal extension (wrote on cpp with templates, ...) from Oracle to PostgreSQL. -- Ben Ali Rachid |
Ben Ali Rachid <souliman239@yahoo.fr> writes: > Craig Ringer wrote : >> - Declare all hook functions that might be dlopen()ed as extern "C" > Thanks for your advices but I'm not sure to have understood. PG_FUNCTION_INFO_V1() generates a function that has to have "C" linkage. So does PG_MODULE_MAGIC. I'm actually not sure how you got the module to load at all with the latter point ... regards, tom lane
Tom Lane wrote : > PG_FUNCTION_INFO_V1() generates a function that has to have "C" linkage. > So does PG_MODULE_MAGIC. I'm actually not sure how you got the module > to load at all with the latter point ... Sorry, I forgot this in my previous post : #ifdef __cplusplus extern "C" { #endif -- #ifdef __cplusplus } #endif I also forgot the definition of the function 'get_normal_pair'. So my (correct) cpp file is like below : #include "dll.h" #ifdef __cplusplus extern "C" { #endif PG_MODULE_MAGIC; void get_normal_pair(float8 *x1, float8 *x2); void get_normal_pair(float8 *x1, float8 *x2) { float8 u1, u2, v1, v2, s; do { u1 = (float8) rand() / (float8) MAX_RANDOM_VALUE; u2 = (float8) rand() / (float8) MAX_RANDOM_VALUE; v1 = (2.0 * u1) - 1.0; v2 = (2.0 * u2) - 1.0; s = v1 * v1 + v2 * v2; } while (s >= 1.0); if (s == 0) { *x1 = 0; *x2 = 0; } else { s = sqrt((-2.0 * log(s)) / s); *x1 = v1 * s; *x2 = v2 * s; } } typedef struct { float8 mean; /* mean of the distribution */ float8 stddev; /* stddev of the distribution */ float8 carry_val; /* hold second generated value */ bool use_carry; /* use second generated value */ } normal_rand_fctx; PG_FUNCTION_INFO_V1(normal_rand); Datum normal_rand(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; int call_cntr; int max_calls; normal_rand_fctx *fctx; float8 mean; float8 stddev; float8 carry_val; bool use_carry; MemoryContext oldcontext; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { /* create a function context for cross-call persistence */ funcctx = SRF_FIRSTCALL_INIT(); /* switch to memory context appropriate for multiple function calls. */ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* total number of tuples to be returned */ funcctx->max_calls = PG_GETARG_UINT32(0); /* allocate memory for user context */ fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx)); /* * Use fctx to keep track of upper and lower bounds from call to call. * It will also be used to carry over the spare value we get from the * Box-Muller algorithm so that we only actually calculate a new value * every other call. */ fctx->mean = PG_GETARG_FLOAT8(1); fctx->stddev = PG_GETARG_FLOAT8(2); fctx->carry_val = 0; fctx->use_carry = false; funcctx->user_fctx = fctx; MemoryContextSwitchTo(oldcontext); } /* stuff done on every call of the function */ funcctx = SRF_PERCALL_SETUP(); call_cntr = funcctx->call_cntr; max_calls = funcctx->max_calls; fctx = (normal_rand_fctx*) funcctx->user_fctx; mean = fctx->mean; stddev = fctx->stddev; carry_val = fctx->carry_val; use_carry = fctx->use_carry; if (call_cntr < max_calls) /* do when there is more left to send */ { float8 result; if (use_carry) { /* reset use_carry and use second value obtained on last pass */ fctx->use_carry = false; result = carry_val; } else { float8 normval_1; float8 normval_2; /* Get the next two normal values */ get_normal_pair(&normval_1, &normval_2); /* use the first */ result = mean + (stddev * normval_1); /* and save the second */ fctx->carry_val = mean + (stddev * normval_2); fctx->use_carry = true; } /* send the result */ SRF_RETURN_NEXT(funcctx, Float8GetDatum(result)); } else /* do when there is no more left */ SRF_RETURN_DONE(funcctx); } #ifdef __cplusplus } #endif I have no problem when I load the DLL (no 'missing magic block' error). The server crashes when I try : SELECT normal_rand(5, 10.0, 20.0) or SELECT * FROM normal_rand(5, 10.0, 20.0). -- Ben Ali Rachid |
Ben Ali Rachid <souliman239@yahoo.fr> writes: > I have no problem when I load the DLL (no 'missing magic block' error). The server crashes when I try : SELECT normal_rand(5,10.0, 20.0) or SELECT * FROM normal_rand(5, 10.0, 20.0). Well, the next step would be to get out your debugger and try to identify exactly where it's crashing. regards, tom lane