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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.