Skip to content
Browse files

Experimental support for Numeric data type.

  • Loading branch information...
1 parent a65ef1d commit e3b7548f1dc31fa08e76cbe50cf0b1825f0030c3 @tvondra committed Nov 8, 2011
Showing with 587 additions and 0 deletions.
  1. +82 −0 sql/trimmed_aggregates--1.1.sql
  2. +505 −0 src/trimmed.c
View
82 sql/trimmed_aggregates--1.1.sql
@@ -14,6 +14,11 @@ CREATE OR REPLACE FUNCTION trimmed_append_int64(p_pointer internal, p_element bi
AS 'trimmed_aggregates', 'trimmed_append_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_append_numeric(p_pointer internal, p_element numeric, p_cut_low double precision default 0, p_cut_up double precision default 0)
+ RETURNS internal
+ AS 'trimmed_aggregates', 'trimmed_append_numeric'
+ LANGUAGE C IMMUTABLE;
+
/* average */
CREATE OR REPLACE FUNCTION trimmed_avg_double(p_pointer internal)
RETURNS double precision
@@ -30,6 +35,11 @@ CREATE OR REPLACE FUNCTION trimmed_avg_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_avg_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_avg_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_avg_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE avg_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -48,6 +58,12 @@ CREATE AGGREGATE avg_trimmed(bigint, double precision, double precision) (
FINALFUNC = trimmed_avg_int64
);
+CREATE AGGREGATE avg_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_avg_numeric
+);
+
/* variance */
CREATE OR REPLACE FUNCTION trimmed_var_double(p_pointer internal)
RETURNS double precision
@@ -64,6 +80,11 @@ CREATE OR REPLACE FUNCTION trimmed_var_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_var_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_var_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE var_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -82,6 +103,12 @@ CREATE AGGREGATE var_trimmed(bigint, double precision, double precision) (
FINALFUNC = trimmed_var_int64
);
+CREATE AGGREGATE var_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_numeric
+);
+
/* variance (population estimate) */
CREATE OR REPLACE FUNCTION trimmed_var_pop_double(p_pointer internal)
RETURNS double precision
@@ -98,6 +125,11 @@ CREATE OR REPLACE FUNCTION trimmed_var_pop_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_var_pop_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_var_pop_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_pop_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE var_pop_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -116,6 +148,12 @@ CREATE AGGREGATE var_pop_trimmed(bigint, double precision, double precision) (
FINALFUNC = trimmed_var_pop_int64
);
+CREATE AGGREGATE var_pop_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_pop_numeric
+);
+
/* variance (sample estimate) */
CREATE OR REPLACE FUNCTION trimmed_var_samp_double(p_pointer internal)
RETURNS double precision
@@ -132,6 +170,11 @@ CREATE OR REPLACE FUNCTION trimmed_var_samp_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_var_samp_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_var_samp_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_var_samp_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE var_samp_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -150,6 +193,12 @@ CREATE AGGREGATE var_samp_trimmed(bigint, double precision, double precision) (
FINALFUNC = trimmed_var_samp_int64
);
+CREATE AGGREGATE var_samp_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_var_samp_numeric
+);
+
/* variance */
CREATE OR REPLACE FUNCTION trimmed_stddev_double(p_pointer internal)
RETURNS double precision
@@ -166,6 +215,11 @@ CREATE OR REPLACE FUNCTION trimmed_stddev_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_stddev_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_stddev_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE stddev_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -184,6 +238,12 @@ CREATE AGGREGATE stddev_trimmed(bigint, double precision, double precision) (
FINALFUNC = trimmed_stddev_int64
);
+CREATE AGGREGATE stddev_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_numeric
+);
+
/* variance (population estimate) */
CREATE OR REPLACE FUNCTION trimmed_stddev_pop_double(p_pointer internal)
RETURNS double precision
@@ -200,6 +260,11 @@ CREATE OR REPLACE FUNCTION trimmed_stddev_pop_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_stddev_pop_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_stddev_pop_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_pop_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE stddev_pop_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -218,6 +283,12 @@ CREATE AGGREGATE stddev_pop_trimmed(bigint, double precision, double precision)
FINALFUNC = trimmed_stddev_pop_int64
);
+CREATE AGGREGATE stddev_pop_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_pop_numeric
+);
+
/* variance (sample estimate) */
CREATE OR REPLACE FUNCTION trimmed_stddev_samp_double(p_pointer internal)
RETURNS double precision
@@ -234,6 +305,11 @@ CREATE OR REPLACE FUNCTION trimmed_stddev_samp_int64(p_pointer internal)
AS 'trimmed_aggregates', 'trimmed_stddev_samp_int64'
LANGUAGE C IMMUTABLE;
+CREATE OR REPLACE FUNCTION trimmed_stddev_samp_numeric(p_pointer internal)
+ RETURNS numeric
+ AS 'trimmed_aggregates', 'trimmed_stddev_samp_numeric'
+ LANGUAGE C IMMUTABLE;
+
CREATE AGGREGATE stddev_samp_trimmed(double precision, double precision, double precision) (
SFUNC = trimmed_append_double,
STYPE = internal,
@@ -250,4 +326,10 @@ CREATE AGGREGATE stddev_samp_trimmed(bigint, double precision, double precision)
SFUNC = trimmed_append_int64,
STYPE = internal,
FINALFUNC = trimmed_stddev_samp_int64
+);
+
+CREATE AGGREGATE stddev_samp_trimmed(numeric, double precision, double precision) (
+ SFUNC = trimmed_append_numeric,
+ STYPE = internal,
+ FINALFUNC = trimmed_stddev_samp_numeric
);
View
505 src/trimmed.c
@@ -8,6 +8,8 @@
#include "utils/palloc.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
+#include "utils/numeric.h"
+#include "utils/builtins.h"
#include "nodes/memnodes.h"
#include "fmgr.h"
#include "catalog/pg_type.h"
@@ -30,6 +32,8 @@ PG_MODULE_MAGIC;
#define SLICE_SIZE 1024
+/* FIXME The final functions copy a lot of code - refactor to share. */
+
/* Structures used to keep the data - the 'elements' array is extended
* on the fly if needed. */
@@ -69,89 +73,127 @@ typedef struct struct_int64 {
} struct_int64;
+typedef struct struct_numeric {
+
+ int nelements;
+ int next;
+
+ double cut_lower;
+ double cut_upper;
+
+ Numeric * elements;
+
+} struct_numeric;
+
/* comparators, used for qsort */
static int double_comparator(const void *a, const void *b);
static int int32_comparator(const void *a, const void *b);
static int int64_comparator(const void *a, const void *b);
+static int numeric_comparator(const void *a, const void *b);
/* ACCUMULATE DATA */
PG_FUNCTION_INFO_V1(trimmed_append_double);
PG_FUNCTION_INFO_V1(trimmed_append_int32);
PG_FUNCTION_INFO_V1(trimmed_append_int64);
+PG_FUNCTION_INFO_V1(trimmed_append_numeric);
Datum trimmed_append_double(PG_FUNCTION_ARGS);
Datum trimmed_append_int32(PG_FUNCTION_ARGS);
Datum trimmed_append_int64(PG_FUNCTION_ARGS);
+Datum trimmed_append_numeric(PG_FUNCTION_ARGS);
/* AVERAGE */
PG_FUNCTION_INFO_V1(trimmed_avg_double);
PG_FUNCTION_INFO_V1(trimmed_avg_int32);
PG_FUNCTION_INFO_V1(trimmed_avg_int64);
+PG_FUNCTION_INFO_V1(trimmed_avg_numeric);
Datum trimmed_avg_double(PG_FUNCTION_ARGS);
Datum trimmed_avg_int32(PG_FUNCTION_ARGS);
Datum trimmed_avg_int64(PG_FUNCTION_ARGS);
+Datum trimmed_avg_numeric(PG_FUNCTION_ARGS);
/* VARIANCE */
/* exact */
PG_FUNCTION_INFO_V1(trimmed_var_double);
PG_FUNCTION_INFO_V1(trimmed_var_int32);
PG_FUNCTION_INFO_V1(trimmed_var_int64);
+PG_FUNCTION_INFO_V1(trimmed_var_numeric);
Datum trimmed_var_double(PG_FUNCTION_ARGS);
Datum trimmed_var_int32(PG_FUNCTION_ARGS);
Datum trimmed_var_int64(PG_FUNCTION_ARGS);
+Datum trimmed_var_numeric(PG_FUNCTION_ARGS);
/* population estimate */
PG_FUNCTION_INFO_V1(trimmed_var_pop_double);
PG_FUNCTION_INFO_V1(trimmed_var_pop_int32);
PG_FUNCTION_INFO_V1(trimmed_var_pop_int64);
+PG_FUNCTION_INFO_V1(trimmed_var_pop_numeric);
Datum trimmed_var_pop_double(PG_FUNCTION_ARGS);
Datum trimmed_var_pop_int32(PG_FUNCTION_ARGS);
Datum trimmed_var_pop_int64(PG_FUNCTION_ARGS);
+Datum trimmed_var_pop_numeric(PG_FUNCTION_ARGS);
/* sample estimate */
PG_FUNCTION_INFO_V1(trimmed_var_samp_double);
PG_FUNCTION_INFO_V1(trimmed_var_samp_int32);
PG_FUNCTION_INFO_V1(trimmed_var_samp_int64);
+PG_FUNCTION_INFO_V1(trimmed_var_samp_numeric);
Datum trimmed_var_samp_double(PG_FUNCTION_ARGS);
Datum trimmed_var_samp_int32(PG_FUNCTION_ARGS);
Datum trimmed_var_samp_int64(PG_FUNCTION_ARGS);
+Datum trimmed_var_samp_numeric(PG_FUNCTION_ARGS);
/* STANDARD DEVIATION */
/* exact */
PG_FUNCTION_INFO_V1(trimmed_stddev_double);
PG_FUNCTION_INFO_V1(trimmed_stddev_int32);
PG_FUNCTION_INFO_V1(trimmed_stddev_int64);
+PG_FUNCTION_INFO_V1(trimmed_stddev_numeric);
Datum trimmed_stddev_double(PG_FUNCTION_ARGS);
Datum trimmed_stddev_int32(PG_FUNCTION_ARGS);
Datum trimmed_stddev_int64(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_numeric(PG_FUNCTION_ARGS);
/* population estimate */
PG_FUNCTION_INFO_V1(trimmed_stddev_pop_double);
PG_FUNCTION_INFO_V1(trimmed_stddev_pop_int32);
PG_FUNCTION_INFO_V1(trimmed_stddev_pop_int64);
+PG_FUNCTION_INFO_V1(trimmed_stddev_pop_numeric);
Datum trimmed_stddev_pop_double(PG_FUNCTION_ARGS);
Datum trimmed_stddev_pop_int32(PG_FUNCTION_ARGS);
Datum trimmed_stddev_pop_int64(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_pop_numeric(PG_FUNCTION_ARGS);
/* sample estimate */
PG_FUNCTION_INFO_V1(trimmed_stddev_samp_double);
PG_FUNCTION_INFO_V1(trimmed_stddev_samp_int32);
PG_FUNCTION_INFO_V1(trimmed_stddev_samp_int64);
+PG_FUNCTION_INFO_V1(trimmed_stddev_samp_numeric);
Datum trimmed_stddev_samp_double(PG_FUNCTION_ARGS);
Datum trimmed_stddev_samp_int32(PG_FUNCTION_ARGS);
Datum trimmed_stddev_samp_int64(PG_FUNCTION_ARGS);
+Datum trimmed_stddev_samp_numeric(PG_FUNCTION_ARGS);
+
+/* numeric helper */
+static Numeric create_numeric(int value);
+static Numeric add_numeric(Numeric a, Numeric b);
+static Numeric sub_numeric(Numeric a, Numeric b);
+static Numeric div_numeric(Numeric a, Numeric b);
+static Numeric mul_numeric(Numeric a, Numeric b);
+static Numeric pow_numeric(Numeric a, int b);
+static Numeric sqrt_numeric(Numeric a);
/* These functions use a bit dirty trick to pass the data - the int
@@ -310,6 +352,55 @@ trimmed_append_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_append_numeric(PG_FUNCTION_ARGS)
+{
+
+ struct_numeric * data;
+
+ Numeric element;
+
+ MemoryContext oldcontext;
+ MemoryContext aggcontext;
+
+ GET_AGG_CONTEXT("trimmed_append_numeric", fcinfo, aggcontext);
+
+ oldcontext = MemoryContextSwitchTo(aggcontext);
+
+ if (PG_ARGISNULL(0)) {
+
+ data = (struct_numeric*)palloc(sizeof(struct_numeric));
+ data->elements = (Numeric*)palloc(SLICE_SIZE*sizeof(Numeric));
+ data->nelements = SLICE_SIZE;
+ data->next = 0;
+
+ /* how much to cut */
+ data->cut_lower = PG_GETARG_FLOAT8(2);
+ data->cut_upper = PG_GETARG_FLOAT8(3);
+
+ } else {
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+ }
+
+ if (! PG_ARGISNULL(1)) {
+
+ element = PG_GETARG_NUMERIC(1);
+
+ if (data->next > data->nelements-1) {
+ data->elements = (Numeric*)repalloc(data->elements, sizeof(Numeric)*(data->nelements + SLICE_SIZE));
+ data->nelements = data->nelements + SLICE_SIZE;
+ }
+
+ data->elements[data->next++] = element;
+
+ }
+
+ MemoryContextSwitchTo(oldcontext);
+
+ PG_RETURN_POINTER(data);
+
+}
+
+Datum
trimmed_avg_double(PG_FUNCTION_ARGS)
{
@@ -418,6 +509,45 @@ trimmed_avg_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_avg_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric result, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_avg_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ /* create numeric values */
+ cnt = create_numeric(to-from);
+ result = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ result = add_numeric(result, div_numeric(data->elements[i], cnt));
+ }
+
+ PG_RETURN_NUMERIC(result);
+
+}
+
+Datum
trimmed_var_double(PG_FUNCTION_ARGS)
{
@@ -541,6 +671,49 @@ trimmed_var_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_var_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric result, avg, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_var_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ avg = create_numeric(0);
+ result = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ avg = add_numeric(avg, div_numeric(data->elements[i], cnt));
+ }
+
+ for (i = from; i < to; i++) {
+ result = add_numeric(result, div_numeric(pow_numeric(sub_numeric(data->elements[i],avg),2),cnt));
+ }
+
+ PG_RETURN_NUMERIC(result);
+
+}
+
+Datum
trimmed_var_pop_double(PG_FUNCTION_ARGS)
{
@@ -652,6 +825,47 @@ trimmed_var_pop_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_var_pop_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric sum_x, sum_x2, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_var_pop_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ sum_x = create_numeric(0);
+ sum_x2 = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ sum_x = add_numeric(sum_x, data->elements[i]);
+ sum_x2 = add_numeric(sum_x2, mul_numeric(data->elements[i], data->elements[i]));
+ }
+
+ PG_RETURN_NUMERIC (div_numeric(sub_numeric(mul_numeric(cnt, sum_x2), mul_numeric(sum_x, sum_x)),
+ mul_numeric(cnt, cnt)));
+
+}
+
+Datum
trimmed_var_samp_double(PG_FUNCTION_ARGS)
{
@@ -763,6 +977,47 @@ trimmed_var_samp_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_var_samp_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric sum_x, sum_x2, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_var_samp_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ sum_x = create_numeric(0);
+ sum_x2 = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ sum_x = add_numeric(sum_x, data->elements[i]);
+ sum_x2 = add_numeric(sum_x2, mul_numeric(data->elements[i], data->elements[i]));
+ }
+
+ PG_RETURN_NUMERIC (div_numeric(sub_numeric(mul_numeric(cnt, sum_x2), mul_numeric(sum_x, sum_x)),
+ mul_numeric(cnt, sub_numeric(cnt, create_numeric(1)))));
+
+}
+
+Datum
trimmed_stddev_double(PG_FUNCTION_ARGS)
{
@@ -885,6 +1140,48 @@ trimmed_stddev_int64(PG_FUNCTION_ARGS)
}
+Datum
+trimmed_stddev_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric result, avg, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_stddev_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ avg = create_numeric(0);
+ result = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ avg = add_numeric(avg, div_numeric(data->elements[i], cnt));
+ }
+
+ for (i = from; i < to; i++) {
+ result = add_numeric(result, div_numeric(pow_numeric(sub_numeric(data->elements[i], avg), 2), cnt));
+ }
+
+ PG_RETURN_NUMERIC (sqrt_numeric(result));
+
+}
Datum
trimmed_stddev_pop_double(PG_FUNCTION_ARGS)
@@ -998,6 +1295,48 @@ trimmed_stddev_pop_int64(PG_FUNCTION_ARGS)
}
Datum
+trimmed_stddev_pop_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric sum_x, sum_x2, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_stddev_pop_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ sum_x = create_numeric(0);
+ sum_x2 = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ sum_x = add_numeric(sum_x, data->elements[i]);
+ sum_x2 = add_numeric(sum_x2, mul_numeric(data->elements[i], data->elements[i]));
+ }
+
+ PG_RETURN_NUMERIC (sqrt_numeric(div_numeric(sub_numeric(mul_numeric(cnt, sum_x2),
+ mul_numeric(sum_x, sum_x)),
+ pow_numeric(cnt, 2))));
+
+}
+
+Datum
trimmed_stddev_samp_double(PG_FUNCTION_ARGS)
{
@@ -1108,6 +1447,48 @@ trimmed_stddev_samp_int64(PG_FUNCTION_ARGS)
}
+Datum
+trimmed_stddev_samp_numeric(PG_FUNCTION_ARGS)
+{
+
+ int i;
+ Numeric sum_x, sum_x2, cnt;
+ int from, to;
+
+ struct_numeric * data;
+
+ CHECK_AGG_CONTEXT("trimmed_stddev_samp_numeric", fcinfo);
+
+ if (PG_ARGISNULL(0)) {
+ PG_RETURN_NULL();
+ }
+
+ data = (struct_numeric*)PG_GETARG_POINTER(0);
+
+ from = floor(data->next * data->cut_lower);
+ to = data->next - floor(data->next * data->cut_upper);
+
+ if (from > to) {
+ PG_RETURN_NULL();
+ }
+
+ cnt = create_numeric(to - from);
+ sum_x = create_numeric(0);
+ sum_x2 = create_numeric(0);
+
+ qsort(data->elements, data->next, sizeof(Numeric), &numeric_comparator);
+
+ for (i = from; i < to; i++) {
+ sum_x = add_numeric(sum_x, data->elements[i]);
+ sum_x2 = add_numeric(sum_x2, pow_numeric(data->elements[i], 2));
+ }
+
+ PG_RETURN_NUMERIC (sqrt_numeric(div_numeric(sub_numeric(mul_numeric(cnt, sum_x2),
+ pow_numeric(sum_x, 2)),
+ mul_numeric(cnt, sub_numeric(cnt, create_numeric(1))))));
+
+}
+
static int double_comparator(const void *a, const void *b) {
double af = (*(double*)a);
double bf = (*(double*)b);
@@ -1125,3 +1506,127 @@ static int int64_comparator(const void *a, const void *b) {
int64 bf = (*(int64*)b);
return (af > bf) - (af < bf);
}
+
+static int numeric_comparator(const void *a, const void *b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(*(Numeric*)a);
+ fcinfo.arg[1] = NumericGetDatum(*(Numeric*)b);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetInt32(numeric_cmp(&fcinfo));
+
+}
+
+static Numeric create_numeric(int value) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 1;
+ fcinfo.arg[0] = Int32GetDatum(value);
+ fcinfo.argnull[0] = false;
+
+ /* return the result */
+ return DatumGetNumeric(int4_numeric(&fcinfo));
+
+}
+
+static Numeric add_numeric(Numeric a, Numeric b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.arg[1] = NumericGetDatum(b);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_add(&fcinfo));
+
+}
+
+static Numeric div_numeric(Numeric a, Numeric b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.arg[1] = NumericGetDatum(b);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_div(&fcinfo));
+
+}
+
+static Numeric mul_numeric(Numeric a, Numeric b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.arg[1] = NumericGetDatum(b);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_mul(&fcinfo));
+
+}
+
+static Numeric sub_numeric(Numeric a, Numeric b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.arg[1] = NumericGetDatum(b);
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_sub(&fcinfo));
+
+}
+
+static Numeric pow_numeric(Numeric a, int b) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 2;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.arg[1] = NumericGetDatum(create_numeric(b));
+ fcinfo.argnull[0] = false;
+ fcinfo.argnull[1] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_power(&fcinfo));
+
+}
+
+static Numeric sqrt_numeric(Numeric a) {
+
+ FunctionCallInfoData fcinfo;
+
+ /* set params */
+ fcinfo.nargs = 1;
+ fcinfo.arg[0] = NumericGetDatum(a);
+ fcinfo.argnull[0] = false;
+
+ /* return the result */
+ return DatumGetNumeric(numeric_sqrt(&fcinfo));
+
+}

0 comments on commit e3b7548

Please sign in to comment.
Something went wrong with that request. Please try again.