Postgres 8.3 - C function taking and returning arrays - Mailing list pgsql-novice

From s anwar
Subject Postgres 8.3 - C function taking and returning arrays
Date
Msg-id 3e3c86f90802281153o15e70724u425cdd0173bb2373@mail.gmail.com
Whole thread Raw
Responses Re: Postgres 8.3 - C function taking and returning arrays  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-novice
I have written a PostgreSQL 8.3beta2 server side function named array_times_scalar (source included below). It works, but I haven't found sufficient examples to be certain that I am not leaking memory. I was wondering if someone can either point me to examples or take a look at the code below.

I am, however, getting incorrect values if I select a particular array index out of the result of this function. That is, "select (array_times_scalar('{344,52,25}'::smallint[],0.001::double precision))[1];" is not the same as the first element of "select array_times_scalar('{344,52,25}'::smallint[],0.001::double precision);". I was hoping if someone could shed a light on why that may be.

As a side-note: I've written similar function in plpgsql, which produces correct results when I extract any element of the returned array. However, I need the speed of a C-function since this function may be run on millions of records at a time.

Thanks.


create or replace function array_times_scalar(smallint[], double precision) returns real[]
as '/var/lib/pgsql/test_func',
'array_times_scalar' language C immutable strict;

Datum array_times_scalar(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(array_times_scalar);

/**
 ** Returns the input array with every element multiplied
 ** by the specified scale.
 **/
Datum
array_times_scalar(PG_FUNCTION_ARGS){
        ArrayType  *input;
        Datum      *i_data;
        bool       *nulls;
        float8      scale = 0;
        ArrayType  *result;
        Datum      *result_data;
        int         ndims, *dims, *lbs;
        Oid         i_eltype, s_eltype, o_eltype;
        int16       i_typlen, o_typlen;
        bool        i_typbyval, o_typbyval;
        char        i_typalign, o_typalign;
        int         i, n;

        /* return null on null input */
        if (PG_ARGISNULL(0) || PG_ARGISNULL(1)){
                PG_RETURN_NULL();
        }

        /* get input args */
        input = PG_GETARG_ARRAYTYPE_P(0);

        /* get input array element type */
        i_eltype = ARR_ELEMTYPE(input);
        get_typlenbyvalalign(i_eltype, &i_typlen, &i_typbyval, &i_typalign);

        /* validate input data type */
        switch(i_eltype){
        case INT2OID:
        case INT4OID:
        case FLOAT4OID:
        case FLOAT8OID:
                break;
        default:
                elog(ERROR, "Invalid input data type");
                break;
        }

        /* get scale data type */
        s_eltype = get_fn_expr_argtype(fcinfo->flinfo, 1);

        /* validate the scale data type */
        switch(s_eltype){
        case INT2OID:   scale = PG_GETARG_INT16(1);  break;
        case INT4OID:   scale = PG_GETARG_INT32(1);  break;
        case FLOAT4OID: scale = PG_GETARG_FLOAT4(1); break;
        case FLOAT8OID: scale = PG_GETARG_FLOAT8(1); break;
        default:
                elog(ERROR, "Invalid scale type");
                break;
        }

        /* get output array element type */
        if (i_eltype == FLOAT8OID || s_eltype == FLOAT8OID){
                o_eltype = FLOAT8OID;
        }
        else if (i_eltype == FLOAT4OID || s_eltype == FLOAT4OID){
                o_eltype = FLOAT4OID;
        }
        else {
                o_eltype = INT4OID;
        }
        get_typlenbyvalalign(o_eltype, &o_typlen, &o_typbyval, &o_typalign);

        /* get various pieces of data from the input array */
        ndims = ARR_NDIM(input);
        dims = ARR_DIMS(input);
        lbs = ARR_LBOUND(input);

        /* get src data */
        deconstruct_array(input, i_eltype, i_typlen, i_typbyval, i_typalign, &i_data, &nulls, &n);

        /* construct result array */
        result_data = (Datum *)palloc(n * sizeof(Datum));

        /* apply scale */
        for(i=0; i<n; i++){
                if (nulls[i]){
                        result_data[i] = PointerGetDatum(NULL);
                }
                else {
                        double v = 0;

                        switch(i_eltype){
                        case INT2OID:   v = DatumGetInt16(i_data[i]); break;
                        case INT4OID:   v = DatumGetInt32(i_data[i]); break;
                        case FLOAT4OID: v = DatumGetFloat4(i_data[i]); break;
                        case FLOAT8OID: v = DatumGetFloat8(i_data[i]); break;
                        }

                        v *= scale;

                        switch(o_eltype){
                        case INT4OID:   result_data[i] = Int32GetDatum((int32)v); break;
                        case FLOAT4OID: result_data[i] = Float4GetDatum((float4)v); break;
                        case FLOAT8OID: result_data[i] = Float8GetDatum((float8)v); break;
                        }
                }
        }

        result = construct_md_array((void *)result_data, nulls, ndims, dims, lbs, o_eltype, o_typlen, o_typbyval, o_typalign);

        pfree(i_data);
        pfree(result_data);
        pfree(nulls);

        PG_RETURN_ARRAYTYPE_P(result);
}

pgsql-novice by date:

Previous
From: Ennio-Sr
Date:
Subject: pidof not working for postgresql-8.3 ?
Next
From: messias
Date:
Subject: Monitoring new records