I can return multiple strings w/o problem.<br /><br />But if I tried to return multiple bytea rows. It only return 10
rowswith empty data.<br />Please see the code below.<br /><br />Also, when I compile it, I had warning:<br />test.c
:121:warning: assignment makes pointer from integer without a cast <br />The line is: <br />tuple = heap_form_tuple(
tupdesc,&dtvalues, &isNull );<br /><br />Strange.. compiled in a linux box. <br /><br /><br />If I use: tuple =
BuildTupleFromCStrings(attinmeta,values); <br />it can work but it's string and I want to use bytea.<br /><br />Also,
doI need to free char** values or let postgresql do the job?<br /><br />Thanks<br /><br />Billow<br /><br /><br
/>============================================================================================<br
/>/************************************************************<br/>-- select * from test(1,2,'asdfdsaf') as (id
bytea);<br/>CREATE OR REPLACE FUNCTION test(int,int,text)<br /> RETURNS setof record<br /> AS
'gr_indexsearch.so','test' <br /> LANGUAGE 'C' IMMUTABLE CALLED ON NULL INPUT;<br
/>*************************************************************/<br/><br />// PostgreSQL includes<br />#include
"postgres.h"<br/>#include "fmgr.h" <br /><br />// Tuple building functions and macros<br />#include "funcapi.h"<br
/><br/>#include "utils/builtins.h"<br /><br /><br />#include <string.h><br /><br />#define _textout(str)
DatumGetPointer(DirectFunctionCall1(textout,PointerGetDatum(str))) <br /><br />#ifndef SET_VARSIZE<br />#define
SET_VARSIZE(v,l)(VARATT_SIZEP(v) = (l))<br />#endif<br /><br />/* SortMem got renamed in PostgreSQL 8.0 */<br />#ifndef
SortMem<br/> #define SortMem 16 * 1024<br />#endif<br /><br />#ifdef PG_MODULE_MAGIC <br />PG_MODULE_MAGIC;<br
/>#endif<br/><br /><br />// forward declaration to keep compiler happy<br />Datum c_complex_add( PG_FUNCTION_ARGS );<br
/><br/>PG_FUNCTION_INFO_V1( test );<br />Datum test( PG_FUNCTION_ARGS )<br />{<br /> // things we need to deal with
constructingour composite type <br /> TupleDesc tupdesc;<br /> HeapTuple tuple;<br />
Tuplestorestate *tupstore = NULL;<br /> ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;<br />
<br/> MemoryContext per_query_ctx; <br /> MemoryContext oldcontext;<br /> <br /> // Get arguments. If we
declareour function as STRICT, then<br /> // this check is superfluous.<br /> if( PG_ARGISNULL(0) ||<br />
PG_ARGISNULL(1)|| <br /> PG_ARGISNULL(2)) <br /> {<br /> PG_RETURN_NULL();<br /> }<br /><br /> // Get
arguments:TimeStart and TimeEnd<br /> int32 TimeStart = PG_GETARG_INT32(0);<br /> int32 TimeEnd =
PG_GETARG_INT32(1);<br/><br /> // Get Search query<br /> char *query = _textout(PG_GETARG_TEXT_P(2)); <br />
<br/> <br /> /* check to see if caller supports us returning a tuplestore */<br /> if (!rsinfo ||
!(rsinfo->allowedModes& SFRM_Materialize))<br /> ereport(ERROR,<br />
(errcode(ERRCODE_SYNTAX_ERROR),<br /> errmsg("materialize mode required, but it is not " \<br />
"allowed in this context")));<br /><br /> /* let the caller know we're sending back a tuplestore */
<br/> rsinfo->returnMode = SFRM_Materialize;<br /> <br /> per_query_ctx = fcinfo->flinfo->fn_mcxt;<br
/> oldcontext = MemoryContextSwitchTo(per_query_ctx);<br /><br /> /* get the requested return tuple description */
<br/> tupdesc = rsinfo->expectedDesc;<br /> <br /> /* OK, use it */<br /> AttInMetadata *attinmeta =
TupleDescGetAttInMetadata(tupdesc);<br/> <br /> /* initialize our tuplestore */<br /> tupstore =
tuplestore_begin_heap(true,false, SortMem); <br /> <br /> char strtest[] = "This is a test!";<br /> int
strleng= strlen(strtest);<br /> <br /> int rows = 10;<br /> //char** values = (char **) palloc(rows *
sizeof(char*));<br /> <br /> bytea** values = (bytea **) palloc(rows * sizeof(bytea *)); <br /> Datum
dtvalues;<br/> bool isNull;<br /> <br /> int i;<br /> for(i=0; i<rows; i++)<br /> {<br />
//values[i]= palloc(strleng * sizeof(char));<br /> //strncpy(values[i], strtest, strleng); <br
/> /* construct the tuple */<br /> //tuple = BuildTupleFromCStrings(attinmeta, values);<br /> /*
nowstore it */<br /> //tuplestore_puttuple(tupstore, tuple);<br /> <br /> values[i] = (bytea
*)palloc( strleng + VARHDRSZ ); <br /> SET_VARSIZE(values[i], strleng + VARHDRSZ);<br /> memcpy(
VARDATA(values[i]),strtest, strleng );<br /> dtvalues = PointerGetDatum(values[i]);<br /><br />
tuple= heap_form_tuple( tupdesc, &dtvalues, &isNull ); <br /><br /> /* now store it */<br />
oldcontext = MemoryContextSwitchTo(per_query_ctx);<br /> tuplestore_puttuple(tupstore, tuple);<br />
MemoryContextSwitchTo(oldcontext);<br /><br /> heap_freetuple(tuple); <br /> }<br /> <br />
tuplestore_donestoring(tupstore);<br/> <br /> /* now go build it */<br /> rsinfo->setResult = tupstore;<br
/><br/> /*<br /> * SFRM_Materialize mode expects us to return a NULL Datum. The actual <br /> * tuples are
inour tuplestore and passed back through rsinfo->setResult.<br /> * rsinfo->setDesc is set to the tuple
descriptionthat we actually used<br /> * to build our tuples with, so the caller can verify we did what it was <br
/> * expecting.<br /> */<br /> rsinfo->setDesc = tupdesc;<br /> MemoryContextSwitchTo(oldcontext);<br
/><br/> return (Datum) 0;<br />}<br />