[pgsql-jp: 41250] Re: ユーザー定義関数の作り方

Tomoaki Sato sato @ sraoss.co.jp
2012年 10月 15日 (月) 22:59:10 JST


佐藤です。

> 山田です。具体策を示していただきありがとうございます。
> お陰さまで、整数配列の加算は上手く出来ました。
> 
> とても便利なコマンドを紹介していただいたのですが、経験不足のため、
> src/backend/utils/adt/arrayfuncs.cなどを理解するのに時間がかかってお
> ります。
> 
> ところで、
> resultをfloat8
> DatumGetInt32をDatumGetFlaot8
> PG_RETURN_INT32をPG_RETURN_Float8
> として、実数配列の加算を行ったところ、無意味に大きな整数を示します。
> 
> そのまま、実数にも適用できるのでしょうか?
> ご教授いただければ幸いです。

データ型に応じた処理を行っていないのではないでしょうか。以下のようにデー
タ型に応じて処理を分ける必要があります。

  switch (elmtyp)
  {
      case INT2OID:
          result = Int16GetDatum(
              DatumGetInt16(result) + DatumGetInt16(elemsp[i]));
          break;
      case INT4OID:
          result = Int32GetDatum(
              DatumGetInt32(result) + DatumGetInt32(elemsp[i]));
          break;

試しに書いみたコードを添付しておきます。

# と書きましたが、ML に承認待ちになってしまったので、メールの最後にコー
# ドを貼りつけておきます。

> >>よく考えると、配列の要素を足すだけなら、C で関数を作らずに SQL、
> 将来、C言語に依存した関数を作りたいためです。御手数をおかけいたしま
> す。
> 
> >>イテレーター
> STLのイテレーターのことでしょうか?
> 現時点で解決しなければならない課題ではありませんが、参照先などあれば
> 教えてもらえないでしょうか?

ヘッダファイル array.h 内の array_create_iterator、array_iterate 関数
のことです。

----------------------------- from here ------------------------------
#include "postgres.h"
#include "fmgr.h"
#include "utils/array.h"
#include "catalog/pg_type.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

PG_FUNCTION_INFO_V1(sum_array);

Datum
sum_array(PG_FUNCTION_ARGS)
{
	ArrayType *arg;
	Oid elmtyp;
	int16 elmlen;
	bool elmbyval;
	char elmalign;
	Datum *elemsp;
	bool *nullsp;
	int nelemsp;
	Datum result;
	int i;

	if (PG_ARGISNULL(0))
	{
		PG_RETURN_NULL();
	}

	arg = PG_GETARG_ARRAYTYPE_P(0);

	elmtyp = ARR_ELEMTYPE(arg);
	switch (elmtyp)
	{
		case INT2OID:
		case INT4OID:
		case INT8OID:
		case FLOAT4OID:
		case FLOAT8OID:
			break;
		default:
			elog(ERROR, "could not determine data type of input");
			break;
	}

	get_typlenbyvalalign(elmtyp, &elmlen, &elmbyval, &elmalign);
	deconstruct_array(arg, elmtyp, elmlen, elmbyval, elmalign,
					  &elemsp, &nullsp, &nelemsp);

	result = 0;
	for (i = 0; i < nelemsp; i++)
	{
		if (nullsp[i])
		{
			elog(DEBUG1, "elemsp[%d]: NULL", i);
			continue;
		}

		switch (elmtyp)
		{
			case INT2OID:
				result = Int16GetDatum(
					DatumGetInt16(result) + DatumGetInt16(elemsp[i]));
				break;
			case INT4OID:
				result = Int32GetDatum(
					DatumGetInt32(result) + DatumGetInt32(elemsp[i]));
				break;
			case INT8OID:
				result = Int64GetDatum(
					DatumGetInt64(result) + DatumGetInt64(elemsp[i]));
				break;
			case FLOAT4OID:
				result = Float4GetDatum(
					DatumGetFloat4(result) + DatumGetFloat4(elemsp[i]));
				break;
			case FLOAT8OID:
				result = Float8GetDatum(
					DatumGetFloat8(result) + DatumGetFloat8(elemsp[i]));
				break;
			default:
				break;
		}
	}

	pfree(elemsp);
	pfree(nullsp);

	PG_RETURN_DATUM(result);
}
------------------------------ to here -------------------------------


----
Tomoaki Sato <sato @ sraoss.co.jp>
SRA OSS, Inc. Japan


pgsql-jp メーリングリストの案内