Skip to content

Commit

Permalink
=Added faceted_count
Browse files Browse the repository at this point in the history
  • Loading branch information
ArturFormella committed Oct 13, 2017
1 parent 7add770 commit 495d7df
Show file tree
Hide file tree
Showing 3 changed files with 1,504 additions and 0 deletions.
125 changes: 125 additions & 0 deletions aggs_for_arrays--1.4.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/* aggs_for_arrays--1.3.0.sql */

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION aggs_for_arrays" to load this file. \quit

CREATE OR REPLACE FUNCTION
array_to_hist(anyarray, anyelement, anyelement, int)
RETURNS int[]
AS 'aggs_for_arrays', 'array_to_hist'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_hist_2d(anyarray, anyarray, anyelement, anyelement, anyelement, anyelement, int, int)
RETURNS int[]
AS 'aggs_for_arrays', 'array_to_hist_2d'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_mean(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_mean'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_median(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_median'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
sorted_array_to_median(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'sorted_array_to_median'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_mode(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_mode'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
sorted_array_to_mode(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'sorted_array_to_mode'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_percentile(anyarray, float)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_percentile'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
sorted_array_to_percentile(anyarray, float)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'sorted_array_to_percentile'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_percentiles(anyarray, float[])
RETURNS DOUBLE PRECISION[]
AS 'aggs_for_arrays', 'array_to_percentiles'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
sorted_array_to_percentiles(anyarray, float[])
RETURNS DOUBLE PRECISION[]
AS 'aggs_for_arrays', 'sorted_array_to_percentiles'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_min(anyarray)
RETURNS anyelement
AS 'aggs_for_arrays', 'array_to_min'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_max(anyarray)
RETURNS anyelement
AS 'aggs_for_arrays', 'array_to_max'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_min_max(anyarray)
RETURNS anyarray
AS 'aggs_for_arrays', 'array_to_min_max'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_count(anyarray)
RETURNS integer
AS 'aggs_for_arrays', 'array_to_count'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_skewness(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_skewness'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
array_to_kurtosis(anyarray)
RETURNS DOUBLE PRECISION
AS 'aggs_for_arrays', 'array_to_kurtosis'
LANGUAGE c IMMUTABLE;

CREATE OR REPLACE FUNCTION
faceted_count_transfn(internal, anyarray)
RETURNS internal
AS 'aggs_for_vecs', 'faceted_count_transfn'
LANGUAGE c;

CREATE OR REPLACE FUNCTION
faceted_count_finalfn(internal, anyarray)
RETURNS anyarray
AS 'aggs_for_vecs', 'faceted_count_finalfn'
LANGUAGE c;

CREATE AGGREGATE faceted_count(anyarray) (
sfunc = faceted_count_transfn,
stype = internal,
finalfunc = faceted_count_finalfn,
finalfunc_extra
);
171 changes: 171 additions & 0 deletions faceted_count.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@

#include "uthash.h"

Datum faceted_count_transfn(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(faceted_count_transfn);

typedef struct hashMap {
int id; /* key */
int value;
UT_hash_handle hh; /* makes this structure hashable */
} hashMap;

typedef struct VecArrayBuildState2 {
Oid inputElementType;
hashMap *keys;
} VecArrayBuildState2;

void delete_all(hashMap *users);
void delete_all(hashMap *users)
{
hashMap *current_user, *tmp;

HASH_ITER(hh, users, current_user, tmp) {
HASH_DEL(users,current_user); // delete it (users advances to next)
free(current_user); // free it
}
}

ArrayType * createArray(VecArrayBuildState2 *state);
ArrayType * createArray(VecArrayBuildState2 *state)
{
int i = 0;
int size = HASH_COUNT(state->keys);
int dims[2];
int lbs[2];
char elemTypeAlignmentCode;
int real_size = size*2;
int16 elemTypeWidth;
ArrayType *result;
bool elemTypeByValue;
hashMap *s;
Datum elements[real_size];

// elog(WARNING, " size %d", size );
for(s=state->keys; s != NULL; s=(hashMap*)(s->hh.next)) {
// elog(WARNING, " user id %d: value %d", s->id, s->value);
elements[i] = s->id;
elements[i + size] = s->value;
i++;
}
dims[0] = 2; // 2x bigger
dims[1] = size;
lbs[0] = 1;
lbs[1] = 1;

get_typlenbyvalalign(INT4OID, &elemTypeWidth, &elemTypeByValue, &elemTypeAlignmentCode);

result = construct_md_array(elements, NULL, 2, dims, lbs, INT4OID, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode);

return result;
}

Datum
faceted_count_transfn(PG_FUNCTION_ARGS)
{
int i;
hashMap *s;
int32 searchForKey;
bool *currentNulls;
Oid elemTypeId;
int16 elemTypeWidth;
bool elemTypeByValue;
char elemTypeAlignmentCode;
int currentLength;
MemoryContext aggContext;
VecArrayBuildState2 *state = NULL;
ArrayType *currentArray;
Datum *currentVals;

if (!AggCheckCallContext(fcinfo, &aggContext)) {
elog(ERROR, "faceted_count_transfn called in non-aggregate context");
}

// PG_ARGISNULL tests for SQL NULL,
// but after the first pass we can have a
// value that is non-SQL-NULL but still is C NULL.
if (!PG_ARGISNULL(0)) {
state = (VecArrayBuildState2 *)PG_GETARG_POINTER(0);
}

if (PG_ARGISNULL(1)) {
// just return the current state unchanged (possibly still NULL)
PG_RETURN_POINTER(state);
}
currentArray = PG_GETARG_ARRAYTYPE_P(1);

if (state == NULL) {
// Since we have our first not-null argument
// we can initialize the state to match its length.
elemTypeId = ARR_ELEMTYPE(currentArray);
if (elemTypeId != INT2OID &&
elemTypeId != INT4OID &&
elemTypeId != INT8OID ) {
ereport(ERROR, (errmsg("faceted_count input must be array of SMALLINT, INTEGER or BIGINT")));
}
if (ARR_NDIM(currentArray) != 1) {
ereport(ERROR, (errmsg("One-dimensional arrays are required")));
}
state = (VecArrayBuildState2 *)MemoryContextAlloc(aggContext, sizeof(VecArrayBuildState2));
state->inputElementType = elemTypeId;
state->keys = NULL;
} else {
elemTypeId = state->inputElementType;
}

get_typlenbyvalalign(elemTypeId, &elemTypeWidth, &elemTypeByValue, &elemTypeAlignmentCode);
deconstruct_array(currentArray, elemTypeId, elemTypeWidth, elemTypeByValue, elemTypeAlignmentCode,&currentVals, &currentNulls, &currentLength);

for (i = 0; i < currentLength; i++) {
switch (elemTypeId) {
case INT2OID:
searchForKey= DatumGetInt16(currentVals[i]);
break;
case INT4OID:
searchForKey= DatumGetInt32(currentVals[i]);
break;
case INT8OID:
searchForKey= DatumGetInt64(currentVals[i]);
break;
default:
elog(ERROR, "Unknown elemTypeId!");
}
//elog(WARNING, "search: searchForKey: %d, currentLength: %d", searchForKey, currentLength);

HASH_FIND_INT( state->keys, &searchForKey, s );// each element is an ID of tag, add +1 for every ID

if(s == NULL){
s = (hashMap*)malloc(sizeof(hashMap));
if(s != NULL){
s->value = 1;
s->id = searchForKey;
HASH_ADD_INT( state->keys, id, s );
}
}else{
s->value++;
}
}
PG_RETURN_POINTER(state);
}

Datum faceted_count_finalfn(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(faceted_count_finalfn);

Datum
faceted_count_finalfn(PG_FUNCTION_ARGS)
{
ArrayType * result;
VecArrayBuildState2 *state;

Assert(AggCheckCallContext(fcinfo, NULL));

state = PG_ARGISNULL(0) ? NULL : (VecArrayBuildState2 *)PG_GETARG_POINTER(0);

if (state == NULL){
PG_RETURN_NULL();
}
result = createArray(state);
delete_all(state->keys);
PG_RETURN_ARRAYTYPE_P(result);
}

Loading

0 comments on commit 495d7df

Please sign in to comment.