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
Views: Raw Message | Whole Thread | Download mbox | Resend email
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

Browse pgsql-novice by date

  From Date Subject
Next Message Andrej Ricnik-Bay 2008-02-28 21:30:40 Re: Monitoring new records
Previous Message messias 2008-02-28 19:06:42 Monitoring new records