Hi, I'm trying to develop a C module, but when the query result is
more than one tuple the server crashes.
Here is the code:
#include "postgres.h"
#include "gram.h"
#include "utils/builtins.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "access/heapam.h"
#include "fmgr.h"
extern Datum sqlf(PG_FUNCTION_ARGS);
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(sqlf);
Datum
sqlf(PG_FUNCTION_ARGS)
{
char *query = TextDatumGetCString(PG_GETARG_DATUM(0));
const char *result="SELECT name FROM people WHERE age>10";
int ret,proc;
int j,i;
FuncCallContext *funcctx;
int call_cntr;
int max_calls;
TupleDesc tupdesc;
TupleDesc tupledesc;
SPITupleTable *tuptable;
AttInMetadata *attinmeta;
// stuff done only on the first call of the function
if (SRF_IS_FIRSTCALL()) {
MemoryContext oldcontext;
// 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);
SPI_connect();
ret=SPI_execute(result,true,0);
proc=SPI_processed;
// total number of tuples to be returned
funcctx->max_calls = proc;
if (ret > 0 && SPI_tuptable != NULL){
tupdesc = SPI_tuptable->tupdesc;
tuptable = SPI_tuptable;
}
tupledesc = BlessTupleDesc(tupdesc);
MemoryContextSwitchTo(oldcontext);
}
// 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;
j=0;
if (call_cntr < max_calls) { // do when there is more left to send
Datum values[tupdesc->natts];
bool nulls[tupdesc->natts];
HeapTuple tuple;
Datum datum_result;
bool isnull;
tuple=tuptable->vals[j];
for (i = 0; i < tupdesc->natts; i++){
values[i]=SPI_getbinval(tuple,tupledesc,i+1,&isnull);
nulls[i]=false;
}
// build a tuple
tuple= heap_form_tuple(tupledesc,values,nulls);
// make the tuple into a datum
datum_result = HeapTupleGetDatum(tuple);
j++;
SRF_RETURN_NEXT(funcctx, datum_result);
} else { // do when there is no more left
SPI_finish();
SRF_RETURN_DONE(funcctx);
}
}