Skip site navigation (1) Skip section navigation (2)

Postgres 8.3 - C function taking and returning arrays

From: "s anwar" <sanwar(at)gmail(dot)com>
To: pgsql-novice(at)postgresql(dot)org
Subject: Postgres 8.3 - C function taking and returning arrays
Date: 2008-02-28 19:53:51
Message-ID: 3e3c86f90802281153o15e70724u425cdd0173bb2373@mail.gmail.com (view raw or flat)
Thread:
Lists: 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);
}

Responses

pgsql-novice by date

Next:From: Andrej Ricnik-BayDate: 2008-02-28 21:30:40
Subject: Re: Monitoring new records
Previous:From: messiasDate: 2008-02-28 19:06:42
Subject: Monitoring new records

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group