A very simple C function which I copied from the manual.
And I found that it's called twice.

Even in the function:

if (SRF_IS_FIRSTCALL()) {
ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("1")));
}

An example output. You will find two INFO: 1 there......

Why a function is called twice and how to prevent this problem?

Thanks

Billow

test=# select * from retcomposite(1,48);
INFO:  1
INFO:  2
INFO:  3
INFO:  1
INFO:  4
INFO:  2
INFO:  2
INFO:  5
INFO:  3
INFO:  4
INFO:  2
INFO:  5
 f1 | f2 | f3
----+----+-----
 48 | 96 | 144
(1 row)



===============================================================
Code......
===============================================================
/*
CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
    RETURNS SETOF __retcomposite
    AS 'test.so', 'retcomposite'
    LANGUAGE C IMMUTABLE STRICT;
    */

// PostgreSQL includes
#include "postgres.h"
#include "fmgr.h"

// Tuple building functions and macros
#include "access/heapam.h"
#include "funcapi.h"
#include "utils/builtins.h"

#include <sys/socket.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>

#define _textout(str) DatumGetPointer(DirectFunctionCall1(textout,
PointerGetDatum(str)))

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif


PG_FUNCTION_INFO_V1(retcomposite);

Datum
retcomposite(PG_FUNCTION_ARGS)
{
  FuncCallContext *funcctx;
  int call_cntr;
  int max_calls;
  TupleDesc tupdesc;
  AttInMetadata *attinmeta;

  /* stuff done only on the first call of the function */
  if (SRF_IS_FIRSTCALL()) {
    MemoryContext oldcontext;

ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("1")));

    /* create a function context for cross-call persistence
     */
    funcctx = SRF_FIRSTCALL_INIT();

    /* switch to memory context appropriate for multiple
       function calls */
    oldcontext =
        MemoryContextSwitchTo(funcctx->
                              multi_call_memory_ctx);

    /* total number of tuples to be returned */
    funcctx->max_calls = PG_GETARG_UINT32(0);

    /* Build a tuple descriptor for our result type */
    if (get_call_result_type(fcinfo, NULL, &tupdesc) !=
        TYPEFUNC_COMPOSITE)
      ereport(ERROR,
              (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
               errmsg
               ("function returning record called in context "
                "that cannot accept type record")));

    /* generate attribute metadata needed later to produce
       tuples from raw C strings */
    attinmeta = TupleDescGetAttInMetadata(tupdesc);
    funcctx->attinmeta = attinmeta;

    MemoryContextSwitchTo(oldcontext);
  }

ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("2")));


  /* stuff done on every call of the function */
  funcctx = SRF_PERCALL_SETUP();

  call_cntr = funcctx->call_cntr;
  max_calls = funcctx->max_calls;
  attinmeta = funcctx->attinmeta;

  if (call_cntr < max_calls) {  /* do when there is more
                                   left to send */
    char **values;
    HeapTuple tuple;
    Datum result;
ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("3")));

    /* Prepare a values array for building the returned
       tuple. This should be an array of C strings which
       will be processed later by the type input functions. */
    values = (char **) palloc(3 * sizeof(char *));
    values[0] = (char *) palloc(16 * sizeof(char));
    values[1] = (char *) palloc(16 * sizeof(char));
    values[2] = (char *) palloc(16 * sizeof(char));

    snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
    snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
    snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));

    /* build a tuple */
    tuple = BuildTupleFromCStrings(attinmeta, values);

    /* make the tuple into a datum */
    result = HeapTupleGetDatum(tuple);

    /* clean up (this is not really necessary) */
    pfree(values[0]);
    pfree(values[1]);
    pfree(values[2]);
    pfree(values);

ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("4")));


    SRF_RETURN_NEXT(funcctx, result);
  } else {  /* do when there is no more left */
ereport(INFO, (errcode(ERRCODE_IO_ERROR), errmsg("5")));

    SRF_RETURN_DONE(funcctx);
  }
}

Reply via email to