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 |