3

私はpostgresql c関数が初めてで、次の例を開始します。

SQL 内にパラメーター evaluete を受け取り、2 つのフィールドを 2 つの列の合計として個別に返す単純な関数を作成したいと考えています (今のところは単純化するため)。

以下の関数は、チェックを通過する際に問題があります

(get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc) != TYPEFUNC_COMPOSITE)

この行を削除すると、このクエリの結果として 1 つの整数が得られます

select * from pdc_imuanno(2012);

からのエラー

select (a).* from pdc_imuanno(2012) a;

複合型ではないので。

質問は、これが正しくない場合、タプルのテンプレートをどのように準備できるかです

resultTupleDesc = CreateTemplateTupleDesc(2, false);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "abp1", FLOAT4OID, -1, 0);
TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "abp2", FLOAT4OID, -1, 0);

そしてもっと

get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc)

fcinfo とは何ですか? どこから来たのですか?

ソース テーブル:

CREATE TABLE imu.calcolo (
  codfis character varying(16) NOT NULL,
  anno integer NOT NULL,
  abp1 numeric,
  abp2 numeric,
  CONSTRAINT imucalcolo_pkey PRIMARY KEY (codfis, anno)
)
WITH ( OIDS=FALSE );
-------------------------------------------------------
#include "postgres.h"
#include "fmgr.h"

#include "catalog/pg_type.h"
#include "funcapi.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"

#include <math.h>

#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/numeric.h"

#include "access/htup_details.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(test_query);
Datum test_query(PG_FUNCTION_ARGS);

Datum
test_query(PG_FUNCTION_ARGS)
{
  TupleDesc resultTupleDesc, tupledesc;
  bool bisnull, cisnull;
  Oid resultTypeId;
  Datum retvals[2];
  bool retnulls[2];
  HeapTuple rettuple;

  sprintf(query,"SELECT anno, abp1::real, abp2::real "
                "FROM imu.calcolo WHERE anno = %d;",PG_GETARG_INT32(0));

  int ret;
  int proc;
  float abp1 = 0;
  float abp2 = 0;
  SPI_connect();
  ret = SPI_exec(query,0);
  proc = SPI_processed;

  if (ret > 0 && SPI_tuptable != NULL)
  {
    HeapTuple tuple;
    tupledesc = SPI_tuptable->tupdesc;
    SPITupleTable *tuptable = SPI_tuptable;
    for (j = 0; j < proc; j++)
    {
      tuple = tuptable->vals[j];
      abp1 += DatumGetFloat4(SPI_getbinval(tuple, tupledesc, 2, &bisnull));
      abp2 += DatumGetFloat4(SPI_getbinval(tuple, tupledesc, 3, &cisnull));
    }
  }
  resultTupleDesc = CreateTemplateTupleDesc(2, false);
  TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "abp1", FLOAT4OID, -1, 0);
  TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "abp2", FLOAT4OID, -1, 0);

  if (get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc) != TYPEFUNC_COMPOSITE) {
    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                    errmsg("function returning record called in context that cannot accept type record")));
  }
  resultTupleDesc = BlessTupleDesc(resultTupleDesc);
  SPI_finish();
  retvals[0] = Float4GetDatum(abp1);
  retvals[1] = Float4GetDatum(abp2);
  retnulls[1] = bisnull;
  retnulls[2] = cisnull;
  rettuple = heap_form_tuple( resultTupleDesc, retvals, retnulls);
  PG_RETURN_DATUM( HeapTupleGetDatum( rettuple ) );

}

作成機能:

CREATE FUNCTION pdc_imuanno(integer)
RETURNS float
AS 'pdc','test_query'
LANGUAGE C STABLE STRICT;
ALTER FUNCTION pdc_imuanno(integer) OWNER TO www;

クエリ:

select * from pdc_imuanno(2012);

わかりました、単純でばかげたエラーを見つけました。自分で 1 フィールドを返す関数を作成し、2 フィールドを返すように期待しました。

この作成SQLで動作します

CREATE FUNCTION pdc_imuanno(integer)
RETURNS TABLE(abp1 real, abp2 real)
AS 'pdc','test_query'
LANGUAGE C STABLE STRICT;

とにかく、合計する行数が限られている場合に機能し、行数を拡張すると、この時点でクラッシュします

rettuple = heap_form_tuple( resultTupleDesc, retvals, retnulls);

値の型にエラーがあると思います

テーブルフィールドをnumeric::realとしてクエリし、float4として取得し、データとして出力します。

私のエラーはどこですか?

助けてくれてありがとう。

これは、StackOverflow での最初の投稿です。

ルカ

4

1 に答える 1

2

の:

get_call_result_type(fcinfo, &resultTypeId, &resultTupleDesc)

fcinfo- 何がどこから来たのですか?

fcinfoPG_FUNCTION_ARGSv1 呼び出し規約の一部です。これは関数呼び出しのコンテキストであり、パラメーターなどのあらゆる種類の詳細が含まれています。これの多くは、マクロなどによって舞台裏で処理されGETARGますが、ヘルパー関数に渡す必要があります。

質問の残りの部分は、タイプミスなどでわかりにくいです。Cで 2 つの値を加算して結果を返す関数を書きたいと思いますか? もしそうなら、複合型の 2 つのフィールドとして返すことはあまり意味がありません。関連するCREATE TYPEステートメント、CREATE OR REPLACE FUNCTION関数を定義するために使用した宣言を示し、何をしようとしているのか、その理由を説明してください。

(質問を編集する場合は、この回答に返信してコメントを投稿してください。そうしないと、編集したことがわかりません。)

于 2013-11-10T03:13:36.033 に答える