Thread: How to write a c-function to return multiple bytea rows

How to write a c-function to return multiple bytea rows

From
"Billow Gao"
Date:
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 /> 

Re: How to write a c-function to return multiple bytea rows

From
Gregory Stark
Date:
I don't know if it's the proximate source of your problem but your
MemoryContextSwitchTo() calls are mixed up. You're reusing the same oldcontext
variable for both the switch you're doing in the main body and the switch
you're doing in the inner loop. At the very least you should use two different
oldcontext variables, currently I think you're leaving the memory context set
to the per_query_ctx. 

But I think in this situation you're going to end up just doing the whole
thing in per_query_ctx anyways. The only part you can avoid that for is the
pallocing of the heap_form_tuple args and the actual heap_form_tuple call. The
tuple will be copied when you call tuplestore_puttuple (which should be done
in the same context the tuplestore was created in).

--  Gregory Stark EnterpriseDB          http://www.enterprisedb.com Get trained by Bruce Momjian - ask me about
EnterpriseDB'sPostgreSQL training!
 


Re: How to write a c-function to return multiple bytea rows

From
Tom Lane
Date:
"Billow Gao" <billowgy@gmail.com> writes:
> Also, when I compile it, I had warning:
> test.c:121: warning: assignment makes pointer from integer without a cast
> The line is:
> tuple = heap_form_tuple( tupdesc, &dtvalues, &isNull );

That part is because you didn't #include access/heapam.h, where
heap_form_tuple is declared.  If you didn't get a warning about it
not being declared, you do not have warnings turned up high enough.
        regards, tom lane