2

I have the following custom type:

CREATE TYPE int2_lo_hi AS (
  lo int2,
  hi int2
);

I want to pass these as an array (int2_lo_hi[]) to a C function. However, I don't know the correct way to access elements.

Here's my code so far, edited:

Header (no longer used):

typedef struct
{
    short   lo,
            hi;
} Int2_lo_hi;

C:

PG_FUNCTION_INFO_V1(array_test);

PGMODULEEXPORT Datum array_test(PG_FUNCTION_ARGS)
{
    ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);

    if (ARR_NDIM(a) > 1)
    {
        ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("1-dimensional array needed")));
    }

    Datum *datums;
    bool *nulls;
    int elemWidth, count;
    Oid elemType = ARR_ELEMTYPE(a);
    bool elemTypeByVal, isNull;
    char elemAlignmentCode;
    get_typlenbyvalalign(elemType, &elemWidth, &elemTypeByVal, &elemAlignmentCode);
    deconstruct_array(a, elemType, elemWidth, elemTypeByVal, elemAlignmentCode, &datums, &nulls, &count);
    int result = 0;
    HeapTupleHeader lt;
    short *field;

    for (int i = 0; i < count; i++)
    {
        if (nulls[i])
        {
            result = -result;
        }
        else
        {
            lt = DatumGetHeapTupleHeader(datums[i]);
/*          field = (short*)GetAttributeByNum(lt, 1, &isNull);

            if (!isNull)
            {
                //result += *field;
            }

            field = (short*)GetAttributeByNum(lt, 2, &isNull);

            if (!isNull)
            {
                //result += *field;
            }*/
        }
    }

    PG_RETURN_INT32(result);
}

The part that is commented out is throwing an error.

Note: I'm getting an error that indicates that OID is invalid. Its value is 28642010, which I cannot find any documentation reference to.

9
  • 1
    I believe you need to specify the exact array element type in deconstruct_array function instead of ANYELEMENTOID. To determine the array type you may use AARR_ELEMTYPE macros. See here the example written by my colleague of how to use it (in attachement) Commented Sep 1, 2016 at 9:49
  • and the forth argument is probably should be false if you palloc your elements Commented Sep 1, 2016 at 9:59
  • Thanks @IldarMusin. I changed the deconstruct line to deconstruct_array(a, ObjectIdGetDatum(a), 4, false, 'i', &datums, &nulls, &count); and changed to Int2_lo_hi* elem = palloc(sizeof(Int2_lo_hi));, but that creates an error (disconnects the server). Did I miss something in your suggestion? Commented Sep 1, 2016 at 10:45
  • It is hard to say without looking into the code. I would try to debug with gdb and see what happens inside. If you have a repo on github or somewhere else I could look into it later today. Commented Sep 1, 2016 at 12:24
  • 1
    And I meant not ObjectIdGetDatum, but AARR_ELEMTYPE. So it may be something like: Oid typeid = AARR_ELEMTYPE(a); deconstruct_array(a, typeid, 4, false, 'i', &datums, &nulls, &count); Commented Sep 1, 2016 at 12:28

1 Answer 1

4

After minor fixes this code works:

PG_FUNCTION_INFO_V1(array_test);

Datum
array_test(PG_FUNCTION_ARGS)
{
    ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
    Datum  *datums;
    bool   *nulls;
    int     count;
    int16   elemWidth;
    Oid     elemType = ARR_ELEMTYPE(a);
    bool    elemTypeByVal, isNull;
    char    elemAlignmentCode;
    int     result = 0;
    HeapTupleHeader lt;
    short   field;

    if (ARR_NDIM(a) > 1)
        ereport(ERROR, (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), errmsg("1-dimensional array needed")));

    get_typlenbyvalalign(elemType, &elemWidth, &elemTypeByVal, &elemAlignmentCode);
    deconstruct_array(a, elemType, elemWidth, elemTypeByVal, elemAlignmentCode, &datums, &nulls, &count);

    for (int i = 0; i < count; i++)
    {
        if (nulls[i])
        {
            result = -result;
        }
        else
        {
            lt = DatumGetHeapTupleHeader(datums[i]);

            field = DatumGetInt16(GetAttributeByNum(lt, 1, &isNull));
            if (!isNull)
                result += field;

            field = DatumGetInt16(GetAttributeByNum(lt, 2, &isNull));
            if (!isNull)
                result += field;
        }
    }

    PG_RETURN_INT32(result);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks again, @IIdar Musin

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.