0

I was wondering, what changes would be necessary to the following code to sum two float4[] arrays instead of two int[] arrays?

I have tried a few things, but without success.

#include <postgres.h>
#include <fmgr.h>
#include <utils/array.h>

PG_MODULE_MAGIC;

Datum int4_array_add(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(int4_array_add);

/**
 * Returns the sum of two int arrays.
 * by Matt Solnit on Stack Overflow - http://stackoverflow.com/questions/16992339
 */
Datum
int4_array_add(PG_FUNCTION_ARGS)
{
  // The formal PostgreSQL array objects:
  ArrayType *array1, *array2;

  // The array element types (should always be INT4OID):
  Oid arrayElementType1, arrayElementType2;

  // The array element type widths (should always be 4):
  int16 arrayElementTypeWidth1, arrayElementTypeWidth2;

  // The array element type "is passed by value" flags (not used, should always be true):
  bool arrayElementTypeByValue1, arrayElementTypeByValue2;

  // The array element type alignment codes (not used):
  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;

  // 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 = 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);
}

What I have tried is to cast the operation:

sumContent[i] = arrayContent1[i] + arrayContent2[i];

to:

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

and to:

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

but it gives me just 0's and strange negative numbers as the output of my c-function:

create or replace function sumar(float4[],float4[])
returns float4[]
as 'example.so', 'sumar'
Language C strict;
Yu Hao
  • 119,891
  • 44
  • 235
  • 294

1 Answers1

0

This line

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

is surely nonsense - you cannot to sum two datums by this statement, you should to use reverse macro:

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

Next advice - use elog(NOTICE, "sometext") on function begin be sure, so SQL uses really your function.

Pavel Stehule
  • 42,331
  • 5
  • 91
  • 94