Thread: Segmentation fault when using a set-returning C function from a view in 8.4.0
Segmentation fault when using a set-returning C function from a view in 8.4.0
From
Christian Thomsen
Date:
Hello, I have created a set-returning C function and a view that selects all the returned rows. When I use SELECT * FROM theview, the returned rows look fine. But if I use, e.g., SELECT count(*) FROM theview or SELECT sum(a) FROM theview, I get a segmentation fault. LOG: server process (PID 7099) was terminated by signal 11: Segmentation fault Is this a bug? SELECT count(*), sum(a) FROM thefunction() works fine. I have created a small example that demonstrates the problem (see below). If the C function only returns few rows, everything works. If the function returns more rows (e.g., 5,000), I get the segmentation fault. I have expericenced this on 8.4.0: chr=# select version(); version -------------------------------------------------------------------------------------------------------------PostgreSQL 8.4.0on x86_64-unknown-linux-gnu, compiled by GCC gcc (GCC) 4.1.2 20070115 (SUSE Linux), 64-bit chr=# show work_mem ;work_mem ----------256MB EXAMPLE: create table demotbl(a int, b int, c int); create function demosrf() returns setof demotbl language 'c' as '/tmp/demo.so'; create view demoview as select * from demotbl union all select * from demosrf(); The C code is shown below. #include "postgres.h" #include "tupdesc.h" #include "funcapi.h" #include "fmgr.h" #ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif PG_FUNCTION_INFO_V1(demosrf); Datum demosrf(PG_FUNCTION_ARGS) { ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; AttInMetadata*attinmeta; int numberOfAttributes; int i, j; Datum *values; bool *isnull; extern int work_mem; if(rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Contextdoes not accept a set"))); if(!(rsinfo->allowedModes & SFRM_Materialize))ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Materialize not allowed"))); tupdesc = rsinfo->expectedDesc; tupstore = tuplestore_begin_heap(false, false, work_mem); attinmeta = TupleDescGetAttInMetadata(tupdesc); numberOfAttributes = attinmeta->tupdesc->natts; values = (Datum *)palloc(numberOfAttributes * sizeof(Datum)); isnull = (bool *)palloc(numberOfAttributes * sizeof(bool)); // Create rows for(i = 0; i < 10000; i++) {for(j = 0; j < numberOfAttributes; j++) { isnull[j] = false; values[j]= Int32GetDatum(i);}tuplestore_putvalues(tupstore, tupdesc, values, isnull); } rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; return (Datum)0; } Best regards, Christian Thomsen
Re: Segmentation fault when using a set-returning C function from a view in 8.4.0
From
Tom Lane
Date:
Christian Thomsen <chr@cs.aau.dk> writes: > I have created a set-returning C function and a view that selects all > the returned rows. When I use SELECT * FROM theview, the returned rows > look fine. But if I use, e.g., SELECT count(*) FROM theview or SELECT > sum(a) FROM theview, I get a segmentation fault. > LOG: server process (PID 7099) was terminated by signal 11: > Segmentation fault > Is this a bug? Yeah, in your code: you've violated multiple rules about set-returning functions. Offhand:* using expectedDesc without checking for NULL* creating the tuplestore in the wrong context* failingto set setDesc Also, blindly using expectedDesc instead of constructing your own tuple descriptor is rather badly missing the point. This code will *only* work for a tupdesc consisting of some number of integer columns; if you're passed something else it will fail in more or less horrible ways. What you're supposed to do is construct a tupdesc that accurately describes what you're returning, and use that for the tupstore and pass it back as setDesc. Then the core code can verify it matches expectedDesc. Passing in expectedDesc is only useful for functions that can work with a variety of actual output tupledescriptors. regards, tom lane