forked from pjungwir/aggs_for_arrays
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7add770
commit 495d7df
Showing
3 changed files
with
1,504 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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,¤tVals, ¤tNulls, ¤tLength); | ||
|
||
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); | ||
} | ||
|
Oops, something went wrong.