/*
* Copyright (C) 2016 - Ferndale-Hall (pg_gsl@ferndale-hall.co.uk)
*
* This file is part of pg_gsl.
*
* pg_gsl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pg_gsl is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pg_gsl. If not, see .
*
*/
#include "postgres.h"
#include "fmgr.h"
#include "pg_gsl.h"
#include "catalog/pg_type.h"
#include "utils/geo_decls.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
#include
#include
#include
#include
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
/*
* Function to return the version of this postresql extension
*/
PG_FUNCTION_INFO_V1(pg_x_gsl_version);
Datum pg_x_gsl_version(PG_FUNCTION_ARGS);
Datum
pg_x_gsl_version(PG_FUNCTION_ARGS)
{
int32 newSize;
text *newText;
newSize = strlen(PG_GSL_VERSION) + VARHDRSZ;
newText = (text *) palloc(newSize);
SET_VARSIZE(newText, newSize);
memcpy(VARDATA(newText), PG_GSL_VERSION, strlen(PG_GSL_VERSION));
PG_RETURN_TEXT_P(newText);
}
/*
* Wrapper to call the GSL fft_real_transform() function
*/
Datum pg_gsl_fft_real_transform(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_gsl_fft_real_transform);
Datum pg_gsl_fft_real_transform(PG_FUNCTION_ARGS) {
ArrayType *input;
Datum *i_data;
bool *nulls;
ArrayType *result;
Datum *result_data;
int ndims, *dims, *lbs;
Oid i_eltype, o_eltype = FLOAT8OID;;
int16 i_typlen, o_typlen;
bool i_typbyval, o_typbyval;
char i_typalign, o_typalign;
int i, n;
double *data;
/* Declare the GSL workspaces */
gsl_fft_real_wavetable *real;
gsl_fft_real_workspace *work;
/* return null on null input */
if (PG_ARGISNULL(0)) {
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 */
if (i_eltype != FLOAT8OID) {
elog(ERROR, "Invalid input data type");
}
/* Get the details of the input parameter */
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);
/* Get the input data, nulls not allowed */
data = (double *)palloc(n * sizeof(double));
for (i = 0; i < n; i++) {
if (nulls[i]) {
elog(ERROR, "NULLs not allowed in the input array");
PG_RETURN_NULL();
}
data[i] = DatumGetFloat8(i_data[i]);
}
/* Allocate the GSL workspaces */
work = gsl_fft_real_workspace_alloc(n);
real = gsl_fft_real_wavetable_alloc(n);
/* Call the GSL function */
gsl_fft_real_transform(data, 1, n, real, work);
/* construct result array */
result_data = (Datum *) palloc(n * sizeof(Datum));
/* Put data into return array */
for (i = 0; i < n; i++) {
result_data[i] = Float8GetDatum((float8) data[i]);
}
/* Construct the return values */
result = construct_md_array((void *) result_data, nulls, ndims, dims, lbs,
o_eltype, o_typlen, o_typbyval, o_typalign);
/* Free the GSL workspaces */
gsl_fft_real_workspace_free(work);
gsl_fft_real_wavetable_free(real);
/* Free the postgresql arrays */
pfree(i_data);
pfree(result_data);
pfree(nulls);
pfree(data);
PG_RETURN_ARRAYTYPE_P(result);
}
/*
* Wrapper to call the GSL fft_halfcomplex_inverse() function
*/
Datum pg_gsl_fft_halfcomplex_inverse(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_gsl_fft_halfcomplex_inverse);
Datum pg_gsl_fft_halfcomplex_inverse(PG_FUNCTION_ARGS) {
ArrayType *input;
Datum *i_data;
bool *nulls;
ArrayType *result;
Datum *result_data;
int ndims, *dims, *lbs;
Oid i_eltype, o_eltype = FLOAT8OID;;
int16 i_typlen, o_typlen;
bool i_typbyval, o_typbyval;
char i_typalign, o_typalign;
int i, n;
double *data;
/* Declare the GSL workspaces */
gsl_fft_halfcomplex_wavetable *hc;
gsl_fft_real_workspace *work;
/* return null on null input */
if (PG_ARGISNULL(0)) {
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 */
if (i_eltype != FLOAT8OID) {
elog(ERROR, "Invalid input data type");
}
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);
/* Get the input data, nulls not allowed */
data = (double *)palloc(n * sizeof(double));
for (i = 0; i < n; i++) {
if (nulls[i]) {
elog(ERROR, "NULLs not allowed in the input array");
PG_RETURN_NULL();
}
data[i] = DatumGetFloat8(i_data[i]);
}
/* Allocate the GSL workspaces */
work = gsl_fft_real_workspace_alloc(n);
hc = gsl_fft_halfcomplex_wavetable_alloc(n);
/* Call the GSL function */
gsl_fft_halfcomplex_inverse(data, 1, n, hc, work);
/* construct result array */
result_data = (Datum *) palloc(n * sizeof(Datum));
/* Put data into return array */
for (i = 0; i < n; i++) {
result_data[i] = Float8GetDatum((float8) data[i]);
}
/* Construct the return values */
result = construct_md_array((void *) result_data, nulls, ndims, dims, lbs,
o_eltype, o_typlen, o_typbyval, o_typalign);
/* Free the GSL workspaces */
gsl_fft_halfcomplex_wavetable_free(hc);
gsl_fft_real_workspace_free(work);
/* Free the postgresql arrays */
pfree(i_data);
pfree(result_data);
pfree(nulls);
pfree(data);
PG_RETURN_ARRAYTYPE_P(result);
}