Why my C function is called twice? - Mailing list pgsql-hackers

From Billow Gao
Subject Why my C function is called twice?
Date
Msg-id 677a32120712110859u39e6c490gf90e93bedaab4331@mail.gmail.com
Whole thread Raw
Responses Re: Why my C function is called twice?  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
A very simple C function which I copied from the manual.<br />And I found that it's called twice.<br /><br />Even in
thefunction:<br /><br />if (SRF_IS_FIRSTCALL()) {<br />ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("1"))); <br
/>}<br/><br />An example output. You will find two INFO: 1 there......<br /><br />Why a function is called twice and
howto prevent this problem?<br /><br />Thanks<br /><br />Billow<br /><br />test=# select * from retcomposite(1,48);<br
/>INFO: 1 <br />INFO:  2<br />INFO:  3<br />INFO:  1<br />INFO:  4<br />INFO:  2<br />INFO:  2<br />INFO:  5<br
/>INFO: 3<br />INFO:  4<br />INFO:  2<br />INFO:  5<br /> f1 | f2 | f3<br />----+----+-----<br /> 48 | 96 | 144<br />(1
row)<br/><br /><br /><br />=============================================================== <br />Code......<br
/>===============================================================<br/>/*<br />CREATE OR REPLACE FUNCTION
retcomposite(integer,integer)<br />    RETURNS SETOF __retcomposite<br />    AS 'test.so', 'retcomposite' <br />   
LANGUAGEC IMMUTABLE STRICT;<br />    */<br /><br />// PostgreSQL includes<br />#include "postgres.h"<br />#include
"fmgr.h"<br/><br />// Tuple building functions and macros<br />#include "access/heapam.h" <br />#include "funcapi.h"<br
/>#include"utils/builtins.h"<br /><br />#include <sys/socket.h><br />#include <fcntl.h> <br />#include
<errno.h><br/>#include <sys/select.h><br /><br />#define _textout(str)
DatumGetPointer(DirectFunctionCall1(textout,PointerGetDatum(str))) <br /><br />#ifdef PG_MODULE_MAGIC<br
/>PG_MODULE_MAGIC;<br/>#endif<br /><br /><br />PG_FUNCTION_INFO_V1(retcomposite);<br /><br />Datum<br
/>retcomposite(PG_FUNCTION_ARGS)<br/>{<br />  FuncCallContext *funcctx;<br />  int call_cntr;<br />  int max_calls; <br
/> TupleDesc tupdesc;<br />  AttInMetadata *attinmeta;<br /><br />  /* stuff done only on the first call of the
function*/<br />  if (SRF_IS_FIRSTCALL()) {<br />    MemoryContext oldcontext;<br /><br />ereport(INFO,
(errcode(ERRCODE_IO_ERROR),errmsg("1"))); <br /><br />    /* create a function context for cross-call persistence<br
/>    */<br />    funcctx = SRF_FIRSTCALL_INIT();<br /><br />    /* switch to memory context appropriate for
multiple<br/>       function calls */<br />    oldcontext = <br />        MemoryContextSwitchTo(funcctx-><br
/>                             multi_call_memory_ctx);<br /><br />    /* total number of tuples to be returned */<br
/>   funcctx->max_calls = PG_GETARG_UINT32(0);<br /><br />    /* Build a tuple descriptor for our result type */ <br
/>   if (get_call_result_type(fcinfo, NULL, &tupdesc) !=<br />        TYPEFUNC_COMPOSITE)<br />     
ereport(ERROR,<br/>              (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),<br />               errmsg<br
/>              ("function returning record called in context " <br />                "that cannot accept type
record")));<br/><br />    /* generate attribute metadata needed later to produce<br />       tuples from raw C strings
*/<br/>    attinmeta = TupleDescGetAttInMetadata(tupdesc); <br />    funcctx->attinmeta = attinmeta;<br /><br />   
MemoryContextSwitchTo(oldcontext);<br/>  }<br /><br />ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("2")));<br /><br
/><br/>  /* stuff done on every call of the function */ <br />  funcctx = SRF_PERCALL_SETUP();<br /><br />  call_cntr =
funcctx->call_cntr;<br/>  max_calls = funcctx->max_calls;<br />  attinmeta = funcctx->attinmeta;<br /><br /> 
if(call_cntr < max_calls) {  /* do when there is more <br />                                   left to send */<br
/>   char **values;<br />    HeapTuple tuple;<br />    Datum result;<br />ereport(INFO, (errcode(ERRCODE_IO_ERROR),
errmsg("3")));<br/><br />    /* Prepare a values array for building the returned <br />       tuple. This should be an
arrayof C strings which<br />       will be processed later by the type input functions. */<br />    values = (char **)
palloc(3* sizeof(char *));<br />    values[0] = (char *) palloc(16 * sizeof(char)); <br />    values[1] = (char *)
palloc(16* sizeof(char));<br />    values[2] = (char *) palloc(16 * sizeof(char));<br /><br />    snprintf(values[0],
16,"%d", 1 * PG_GETARG_INT32(1));<br />    snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1)); <br />   
snprintf(values[2],16, "%d", 3 * PG_GETARG_INT32(1));<br /><br />    /* build a tuple */<br />    tuple =
BuildTupleFromCStrings(attinmeta,values);<br /><br />    /* make the tuple into a datum */<br />    result =
HeapTupleGetDatum(tuple);<br /><br />    /* clean up (this is not really necessary) */<br />    pfree(values[0]);<br
/>   pfree(values[1]);<br />    pfree(values[2]);<br />    pfree(values);<br /><br />ereport(INFO,
(errcode(ERRCODE_IO_ERROR),errmsg("4"))); <br /><br /><br />    SRF_RETURN_NEXT(funcctx, result);<br />  } else {  /*
dowhen there is no more left */<br />ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("5")));<br /><br />   
SRF_RETURN_DONE(funcctx);<br/>  }<br />}<br /> 

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: PGparam proposal
Next
From: Simon Riggs
Date:
Subject: Re: archive_command failures report confusing exit status