After I spent a lot of hours to develop my first simple c custom function below I discover a strange behaviour, could someone suggests why?
If I remove this line the function is normally compiled but
>>> elog(INFO, "ROW restituite: %d", SPI_processed);
psql:query.sql:30: connection to server was lost immediately without result.
And a second question please. Compiling I receve the warning
warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘struct VarChar *’ [-Wformat]
related to line
"ORDER BY idot;", args[0], DatumGetInt32(args[1]));
But no way to cast it to integer
not with DatumGetVarCharP nor DatumGetTextP
and without VARDATA here args[0] = VARDATA(PG_GETARG_VARCHAR_P(0)); I get another error
Thanks a lot
luca
CREATE FUNCTION imu.posot_cf_anno(varchar,integer)
RETURNS TABLE(idot integer, validita integer)
AS 'pdc','posot_cf_anno'
LANGUAGE C STABLE STRICT;
// ------------------------------------------
#include "postgres.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "catalog/pg_type.h"
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(posot_cf_anno);
Datum posot_cf_anno(PG_FUNCTION_ARGS);
struct pos_idot {
int32 idot;
int32 validita;
bool argnulls[2];
bool anyargnull;
};
Datum posot_cf_anno(PG_FUNCTION_ARGS) {
int ret;
char query[1024];
Datum args[2];
struct pos_idot *rinargs;
struct pos_idot *rowsinargs[SPI_processed]; // creo un array di pos_idot
SPI_connect();
args[0] = VARDATA(PG_GETARG_VARCHAR_P(0));
args[1] = PG_GETARG_INT32(1);
sprintf(query,"SELECT DISTINCT idot, validita FROM sit.otpos "
"WHERE btrim(codfis) = '%s' AND "
"date_part('year',to_timestamp(validita::double precision)) <= "
"date_part('year',to_timestamp(%d||'-01-01','YYYY-MM-DD')) "
"ORDER BY idot;", args[0], DatumGetInt32(args[1]));
ret = SPI_exec(query, 0);
elog(INFO, "ROW restituite: %d", SPI_processed);
if (ret > 0 && SPI_tuptable != NULL) {
int i, j, call_nr;
for (j = 0; j < SPI_processed; j++)
{
rinargs = palloc0(sizeof(struct pos_idot));
rinargs->idot = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 1, &rinargs->argnulls[0]));
rinargs->validita = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[j], SPI_tuptable->tupdesc, 2, &rinargs->argnulls[1]));
if (rinargs->argnulls[0] || rinargs->argnulls[1]) rinargs->anyargnull = true;
rowsinargs[j] = rinargs;
}
FuncCallContext *funcctx;
struct pos_idot *rargs;
struct pos_idot *rowsargs[SPI_processed]; // creo un array di pos_idot
if (SRF_IS_FIRSTCALL())
{
funcctx = SRF_FIRSTCALL_INIT();
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo( funcctx->multi_call_memory_ctx );
rargs = palloc0(sizeof(struct pos_idot));
rargs->anyargnull = false;
funcctx->user_fctx = rargs;
funcctx->max_calls = SPI_processed; // there are 6 permutations of 3 elements
rargs->idot = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &rargs->argnulls[0]));
rargs->validita = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[1], SPI_tuptable->tupdesc, 2, &rargs->argnulls[1]));
if (rargs->argnulls[0] || rargs->argnulls[1]) rargs->anyargnull = true;
if (get_call_result_type(fcinfo, NULL, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context that cannot accept type record")));
BlessTupleDesc(funcctx->tuple_desc);
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
rargs = funcctx->user_fctx;
call_nr = funcctx->call_cntr;
if (call_nr < funcctx->max_calls) {
HeapTuple rettuple;
Datum retvals[2];
bool retnulls[2];
retvals[0] = Int32GetDatum(rowsinargs[call_nr]->idot); // idot
retnulls[0] = rowsinargs[call_nr]->argnulls[0]; // idot null
retvals[1] = Int32GetDatum(rowsinargs[call_nr]->validita); // validita
retnulls[1] = rowsinargs[call_nr]->argnulls[1]; // validita null
rettuple = heap_form_tuple(funcctx->tuple_desc, retvals, retnulls);
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum( rettuple ));
}
else /* do when there is no more left */
{
SPI_finish();
SRF_RETURN_DONE(funcctx);
}
}
return 0;
}