Unix Technical Forum

Why my C function is called twice?

This is a discussion on Why my C function is called twice? within the pgsql Hackers forums, part of the PostgreSQL category; --> A very simple C function which I copied from the manual. And I found that it's called twice. Even ...


Go Back   Unix Technical Forum > Database Server Software > PostgreSQL > pgsql Hackers

FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 04-15-2008, 10:36 PM
Billow Gao
 
Posts: n/a
Default Why my C function is called twice?

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);
}
}

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 04-15-2008, 10:37 PM
Tom Lane
 
Posts: n/a
Default Re: Why my C function is called twice?

"Billow Gao" <billowgy@gmail.com> writes:
> A very simple C function which I copied from the manual.
> And I found that it's called twice.


You do realize that it's *supposed* to be called twice? Once to
return the first row, and again to say it's done returning rows.

But the info messages you show are strange anyway. I tried your example
here and got the results I'd expect:

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

I think the code you showed must not quite match what you're actually
executing. Maybe you recompiled the code and forgot to do a LOAD or
start a fresh session to bring in the new .so file?

regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 04:03 PM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.2.0
www.UnixAdminTalk.com