Thread: how to return rows of data via function written by language C strict

how to return rows of data via function written by language C strict

From
Christoph Bilz
Date:
Hello,

i want write functions like this:

CREATE FUNCTION foo(text) returns real as '<path>/foo.dll', 'foo'  LANGUAGE C STRICT;"
CREATE FUNCTION foo2(text) returns table(c1 text, c2 int) as '<path>/foo2.dll', 'foo'  LANGUAGE C STRICT;
So far, so clear. I don't want to return one scalar value or SETOF smth, I want to start the function like this:
select * from foo; … and the rows will be returned.
I read the chapter
https://www.postgresql.org/docs/11/spi.html
and especially 

again and again but I found no solution. So, the functions should return rows of data not just „one“ result or composite types.
The documentation regarding usable examples are very sparse, so I found and tried with this pice of code:

ArrayType* pg_array = DatumGetArrayTypeP(_row_val);
c_array = (float *)ARR_DATA_PTR(pg_array);
pg_array_size = ARR_DIMS(pg_array)[0];
—> so it’s clear  how do I get my data via SPI* functionalty, the result set is within the pg_array or the casted c_array.

I found this within funcapi.h:
 /* Type categories for get_call_result_type and siblings */
typedef enum TypeFuncClass
{   TYPEFUNC_SCALAR,            /* scalar result type */   TYPEFUNC_COMPOSITE,         /* determinable rowtype result */   TYPEFUNC_COMPOSITE_DOMAIN,  /* domain over determinable rowtype result */   TYPEFUNC_RECORD,            /* indeterminate rowtype result */   TYPEFUNC_OTHER              /* bogus type, eg pseudotype */
} TypeFuncClass;

and tried:

TupleDesc   tupdesc;
HeapTuple   tuple;
Datum       rs[100];
int         tuplen;
bool        nulls;

if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_RECORD)   ereport(ERROR,   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),       errmsg("function returning record called in context "           "that cannot accept type record")));

BlessTupleDesc(tupdesc);

for (int j = 0; j < 100; j++) {   rs[j] = Float8GetDatum(c_array[j]);
}

tuplen = tupdesc->natts;
nulls = palloc(tuplen * sizeof(bool));

tuple = heap_form_tuple(tupdesc, rs, nulls);

pfree(nulls);

SPI_finish();

PG_RETURN_DATUM(HeapTupleGetDatum(tuple));


But it doesn’t work. Either the get_call_result_type fails because the function definition doesn’t match or the the client process crashes because smth. happens and I don’t know how this stuff should work.
So, due to the lack of examples in general and the sparse documentation about it, any help will be appreciate.
Thanks.



Re: how to return rows of data via function written by language Cstrict

From
Ian Barwick
Date:
On 7/10/19 5:00 AM, Christoph Bilz wrote:
> Hello,
> 
> i want write functions like this:
> 
> |CREATEFUNCTIONfoo(text)returns real as'<path>/foo.dll','foo'LANGUAGE C STRICT;" CREATE FUNCTION foo2(text) returns
table(c1text, c2 int) as '<path>/foo2.dll', 'foo' LANGUAGE C STRICT;|
 
> 
> So far, so clear. I don't want to return one scalar value or SETOF smth, I want to start the function like this:
> 
> select * from foo; … and the rows will be returned.
> 
> I read the chapter
> 
> https://www.postgresql.org/docs/11/spi.html
> 
> and especially
> 
> https://www.postgresql.org/docs/11/xfunc-c.html#id-1.8.3.13.11
> 
> again and again but I found no solution. So, the functions should return rows of data not just „one“ result or
compositetypes.
 
> The documentation regarding usable examples are very sparse, so I found and tried with this pice of code:
> 
> |ArrayType*pg_array =DatumGetArrayTypeP(_row_val);c_array =(float *)ARR_DATA_PTR(pg_array);pg_array_size
=ARR_DIMS(pg_array)[0];|
> 
> —> so it’s clear  how do I get my data via SPI* functionalty, the result set is within the pg_array or the casted
c_array.
> 
> I found this within funcapi.h:
> 
> |/* Type categories for get_call_result_type and siblings */typedef enum TypeFuncClass {TYPEFUNC_SCALAR,/* scalar
resulttype */TYPEFUNC_COMPOSITE,/* determinable rowtype result */TYPEFUNC_COMPOSITE_DOMAIN,/* domain over determinable
rowtyperesult */TYPEFUNC_RECORD,/* indeterminate rowtype result */TYPEFUNC_OTHER /* bogus type, eg pseudotype
*/}TypeFuncClass;|
> 
> 
> and tried:
> 
> |TupleDesc tupdesc;HeapTuple tuple;Datum rs[100];int tuplen;bool
nulls;if(get_call_result_type(fcinfo,NULL,&tupdesc)!=TYPEFUNC_RECORD)ereport(ERROR,(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),errmsg("function
returningrecord called in context ""that cannot accept type record")));BlessTupleDesc(tupdesc);for(int j =0;j
<100;j++){rs[j]=Float8GetDatum(c_array[j]);}tuplen=tupdesc->natts;nulls =palloc(tuplen *sizeof(bool));tuple
=heap_form_tuple(tupdesc,rs,nulls);pfree(nulls);SPI_finish();PG_RETURN_DATUM(HeapTupleGetDatum(tuple));|
> 
> 
> 
> But it doesn’t work. Either the get_call_result_type fails because the function definition doesn’t match or the the
clientprocess crashes because smth. happens and I don’t know how this stuff should work.
 
> So, due to the lack of examples in general and the sparse documentation about it, any help will be appreciate.

A good place to find working examples is the source code of the various contrib modules.


Regards

Ian Barwick

-- 
  Ian Barwick                   https://www.2ndQuadrant.com/
  PostgreSQL Development, 24x7 Support, Training & Services



Re: how to return rows of data via function written by language C strict

From
"David G. Johnston"
Date:
On Tue, Jul 9, 2019 at 1:00 PM Christoph Bilz <christoph.bilz@icloud.com> wrote:
Hello,

i want write functions like this:

CREATE FUNCTION foo(text) returns real as '<path>/foo.dll', 'foo'  LANGUAGE C STRICT;"
CREATE FUNCTION foo2(text) returns table(c1 text, c2 int) as '<path>/foo2.dll', 'foo'  LANGUAGE C STRICT;
So far, so clear. I don't want to return one scalar value or SETOF smth, I want to start the function like this:
select * from foo; … and the rows will be returned.
Maybe SQL or pl/pgSQL would be a better choice then?

Also, if you plan to return more than one row you are, by definition, creating a SETOF (TABLE is just shorthand) function.

Also, for what its worth I have no idea with "smth" means here - but I also don't program C.
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_RECORD)   ereport(ERROR,   (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),       errmsg("function returning record called in context "           "that cannot accept type record")));
The inequality check above seems wrong - you want to error if you are presented with a record, not when you aren't.

But it doesn’t work. Either the get_call_result_type fails because the function definition doesn’t match or the the client process crashes because smth. happens and I don’t know how this stuff should work.
So, due to the lack of examples in general and the sparse documentation about it, any help will be appreciate.

As Ian noted, contrib is usually the recommended source for up-to-date coding examples.

David J.