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?
|
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: