sql - 如何将两个 float4 数组值相加到一个 Datum 数组中? (postgres 中的 c 函数)

标签 sql arrays postgresql

我的问题是关于 PostgreSQL 中的 C 函数,我试图接收 2 个 float4[] 数组作为参数并返回一个 float4[] 数组作为总和array1 + array2(表中的列也设置为 float4[]),但无法实现:

创建函数:

CREATE OR REPLACE FUNCTION sum(float4[], float4[]) RETURNS float4[]
AS 'example.so', 'sum'
LANGUAGE C STRICT;
-- 'example.so' is already on /usr/lib/postgresql/9.1/lib

C 代码:

Datum sumar(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(sumar);
Datum sumar(PG_FUNCTION_ARGS)

{
  ArrayType *array1, *array2;

  // The array element types:
  Oid arrayElementType1, arrayElementType2;

  // The array element type widths:
  int16 arrayElementTypeWidth1, arrayElementTypeWidth2;

  // The array element type:
  bool arrayElementTypeByValue1, arrayElementTypeByValue2;

  // The array element type alignment codes:
  char arrayElementTypeAlignmentCode1, arrayElementTypeAlignmentCode2;

  // The array contents, as PostgreSQL "datum" objects:
  Datum *arrayContent1, *arrayContent2;

  // List of "is null" flags for the array contents:
  bool *arrayNullFlags1, *arrayNullFlags2;

  // The size of each array:
  int arrayLength1, arrayLength2;

  Datum *sumContent;
  int i;
  ArrayType* resultArray;

  // Extract the PostgreSQL arrays from the parameters passed to this function call.
  array1 = PG_GETARG_ARRAYTYPE_P(0);
  array2 = PG_GETARG_ARRAYTYPE_P(1);

  // Determine the array element types.
  arrayElementType1 = ARR_ELEMTYPE(array1);
  get_typlenbyvalalign(arrayElementType1, &arrayElementTypeWidth1, &arrayElementTypeByValue1, &arrayElementTypeAlignmentCode1);
  arrayElementType2 = ARR_ELEMTYPE(array2);
  get_typlenbyvalalign(arrayElementType2, &arrayElementTypeWidth2, &arrayElementTypeByValue2, &arrayElementTypeAlignmentCode2);

  // Extract the array contents (as Datum objects).
  deconstruct_array(array1, arrayElementType1, arrayElementTypeWidth1, arrayElementTypeByValue1, arrayElementTypeAlignmentCode1, &arrayContent1, &arrayNullFlags1, &arrayLength1);
  deconstruct_array(array2,arrayElementType2, arrayElementTypeWidth2, arrayElementTypeByValue2, arrayElementTypeAlignmentCode2, &arrayContent2, &arrayNullFlags2, &arrayLength2);

  //Create a new array of sum results (as Datum objects).
  sumContent = (Datum *) palloc(sizeof(Datum) * arrayLength1);

  // Generate the sums.
  for (i = 0; i < arrayLength1; i++)
  {
    sumContent[i] =  arrayContent1[i] + arrayContent2[i];
  }

  // Wrap the sums in a new PostgreSQL array object.
  resultArray = construct_array(sumContent, arrayLength1, arrayElementType1, arrayElementTypeWidth1, arrayElementTypeByValue1, arrayElementTypeAlignmentCode1);

  // Return the final PostgreSQL array object.
  PG_RETURN_ARRAYTYPE_P(resultArray);
}

当它在末尾返回数组时,它只显示负值(总和是错误的),但是当我传递 2 个 int 数组时它工作正常。我也试过在总和之前转换值,就像:

sumContent[i] =  Float4GetDatum(arrayContent1[i]) + Float4GetDatum(arrayContent2[i];)

sumContent[i] =  DatumGetFloat4arrayContent1[i]) + DatumGetFloat4(arrayContent2[i]);

但它一直给我奇怪的值。

最佳答案

deconstruct_array 之后,您有一个 Datum 值数组,每个值都是一个按值传递的 float4,表示为 Datum

直接添加 Datum 是无效的 - 它是一种您实际上无法对其执行操作的抽象类型。如果 C 编译器允许我们,那么 PostgreSQL 项目就会报错,但它不会(或者更确切地说,它不会在不让其他事情变得更可怕的情况下)。

要获取 float4 类型的 Datum 的 C float,您应该使用 DatumGetFloat4Float4GetDatum,如您所用,将是相反的方向。同样,如果 C 编译器允许我们这样做,该项目就会出错。

(插入关于 PostgreSQL 社区拒绝迁移到 C++ 的子集的恼怒提示,我们可以在此处使用 C++ 更严格的类型转换规则来执行此类操作)。

如果你添加:

elog(LOG, "%f", Float4GetDatum(arrayContent1[i]));

您应该在日志中看到正确的值。

添加它们并存储你想要的结果:

sumContent[i] = Float4GetDatum( DatumGetFloat4(arrayContent1[i]) +
                                DatumGetFloat4(arrayContent2[i]) );

关于sql - 如何将两个 float4 数组值相加到一个 Datum 数组中? (postgres 中的 c 函数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23796712/

相关文章:

sql - 如何使用 postgresql 计算排列?

sql - 如何在 Golang 中缓存到不同 Postgres/MySQL 数据库的连接?

mysql - 在MYSQL中对子查询的计数进行求和

mysql - 如何在 MySQL 上仅获取 2 个表的公共(public)行?

sql - Redshift SQL 查询 - 优化

c - void类型函数如何在没有指针的情况下将值返回到C中的局部变量?

arrays - 检测{}和选择{}[0]之间的区别

c - C 中是否有查找子字符串重叠的函数?

sql - 在 postgresql 中按月和年对查询结果进行分组

postgresql - 自己服务器上的 Nominatim API inSTALlation 错误