1

Can anyone share an example how I can create C function for PostgreSQL which takes array of two integers as input and returns array as output?

For simple integer I have:

#include "postgres.h"
#include <fmgr.h>

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

int
add_one(int arg) {
    arg++;
    return arg;
}

And after compilation in PostgreSQL:

load '/usr/lib/postgresql/9.1/lib/add_one';

    create or replace function add_one(integer)
      returns integer as
    '/usr/lib/postgresql/9.1/lib/add_one', 'add_one'
      language c;

    select add_one(1);

I need something like:

#include "postgres.h"
#include <fmgr.h>

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif

int
add_one(int[] arg) {
    arg[1]++;
    arg[2] = arg[2] + 2
    return arg[];
}

And in PostgreSQL:

load '/usr/lib/postgresql/9.1/lib/add_one';

create or replace function add_one(integer[])
     returns integer[] as
    '/usr/lib/postgresql/9.1/lib/add_one', 'add_one'
      language c;

    select add_one(ARRAY[1::int,1::int]);

I have tried to modify some function from numeric.c, but without any success so far.

1 Answer 1

7

Your code won't even remotely begin to work as written. PostgreSQL doesn't pass Pg-level arrays as int[], it passes them via the function context in PG_FUNCTION_ARGS (fcinfo) and they're accessed via PG_GETARG_ARRAYTYPE_P macros.

For basic extension function guidance see the docs on C language functions.

Take a look at the definition of array_cat in src/backend/utils/adt/array_userfuncs.c, or array_remove in src/backend/utils/adt/arrayfuncs.c. Or numerous other options.

Your skeleton will look something like:

PG_FUNCTION_INFO_V1(add_arrays);

Datum
add_arrays(PG_FUNCTION_ARGS)
{
    ArrayType  *array1, *array2, *resultarray;

    array1 = PG_GETARG_ARRAYTYPE_P(0);
    array2 = PG_GETARG_ARRAYTYPE_P(1);

    /* Loop over the array bodies and do your mapping to generate resultarray here */

    PG_RETURN_ARRAYTYPE_P(resultarray);
}

The PostgreSQL C array API is awful so I won't have time to fill out the function body. The point is that your function signature is dead wrong - you've totally misunderstood how it works, and what you wrote can't possibly even get executed.

It'd then be declared as:

create or replace function add_arrays(integer[], integer[])
returns integer[] as
'add_arrays', 'add_arrays'
language c immutable strict;

The strict is important; the function skeleton I provided doesn't check for null inputs, so you need to tell the executor not to invoke it with them.

It'd be nice if array_map from src/backend/utils/adt/arrayfuncs.c had a map2 or zip variant that did lockstep iteration of two arrays. Unfortunately it doesn't, so you'll need to iterate over them yourself.

After re-reading your question I'm now wondering if you mean a single array of int[] with two elements and you want the integer result that is the sum of the array. If so, take a look at how the intarray module works; it has simplified functions for handling simple integer arrays.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you, your answer is really helpful. I would like to pass one array with 2 elements (two integers) to C function and get back also one array with 2 integers.
@TomasGreif ... and what happens to the integers? What does it do with the integers? Do you want to add a constant to them? In that case, you can use the array_map function to produce your result.
Adds 1 to 1st element and 2 to the 2nd element and returns elements in the same order. For [1,2] I expect [2,4] as result.
@TomasGreif OK, so you'll need to loop over the input array elements and assign values into the result array after constructing the result array. Browse the built-in array functions and those in intarray and you'll see a few useful examples.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.