postgresql c自定义函数中的奇怪行为

时间:2013-11-19 17:00:44

标签: c postgresql

在我花了很多时间开发我的第一个简单的自定义函数之后,我发现了一个奇怪的行为,有人会建议为什么吗?

如果删除此行,则通常会编译该函数,但

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

1 个答案:

答案 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;
}