IamIC IamIC - 3 months ago 10
C Question

Access array of custom type in a PostgreSQL C function

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.

Answer

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