在我花了很多时间开发我的第一个简单的自定义函数之后,我发现了一个奇怪的行为,有人会建议为什么吗?
如果删除此行,则通常会编译该函数,但
>>> elog(INFO, "ROW restituite: %d", SPI_processed);
psql:query.sql:30:与服务器的连接丢失 立即没有结果。
请问第二个问题。 编译我收到警告
warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘struct VarChar *’ [-Wformat]
与行相关
"ORDER BY idot;", args[0], DatumGetInt32(args[1]));
但无法将其转换为整数
不是使用DatumGetVarCharP也不是使用DatumGetTextP
并且没有VARDATA这里args [0] = VARDATA(PG_GETARG_VARCHAR_P(0));我收到另一个错误
非常感谢
卢卡
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;
}
答案 0 :(得分:1)
我很确定
struct pos_idot *rowsinargs[SPI_processed]; // creo un array di pos_idot
错了,逻辑可能也错了。您只需执行一次查询,因此必须将查询执行推送到SRF_IS_FIRSTCALL()路径。
args[0] = VARDATA(PG_GETARG_VARCHAR_P(0));
也很糟糕。 varchar不是零终止字符串!所以你不能直接在sprintf中使用它。有很好的宏text_to_cstring。 sprintf对PostgreSQL内部类型一无所知 - 你应该将参数转换为C类型。
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]));
应该是
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;", text_to_cstring(PG_GETARG_TEXT_PP(0)), DatumGetInt32(args[1]));
动态数组分配
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int x;
int y;
} mystruct;
void main()
{
mystruct **array;
/* inside pg use palloc instead malloc */
array = malloc(sizeof(mystruct*) * 10);
array[0] = malloc(sizeof(mystruct));
array[0]->x = 10;
array[0]->y = 20;
}