GithubHelp home page GithubHelp logo

istore's Introduction

CI

istore

The idea of istore is to have an integer based hstore (thus the name) which supports operators like + and aggregates like SUM.

The textual representation of an istore is the same as for hstore e.g.

"-5"=>"-25", "0"=>"10", "5"=>"0", "100"=>"30"

On istore both keys and values are represented and stored as integer. The extension comes with two types istore and bigistore the former having int and the latter bigint as values, keys are int for both.

The use case an optimization for istore is an analytical workload. Think of it as showing distributions of whatever can be represented as integer.

Example

Say you have an event log table where you'd aggregate events with some id and segmentation by date.

CREATE TABLE event_log AS
SELECT
  d::date as date,
  j as segment,
  i as id, (random()*1000)::int as count,
  (random()*100000)::int as revenues
FROM
  generate_series(1,50) i,
  generate_series(1,1000) j,
  generate_series(current_date - 99, current_date, '1 day') d;

Using istore you would use the id as key and count / revenues as values.

CREATE TABLE istore_event_log AS
SELECT
  date,
  segment,
  istore(array_agg(id), array_agg(count)) as counts,
  istore(array_agg(id), array_agg(revenues)) as revenues
FROM event_log
GROUP BY date, segment;

To summarize the count for a specific id you would write

istore_test=# SELECT SUM(counts->35) from istore_event_log ;
    sum
----------
  50213687
(1 row)

Time: 29,032 ms

instead of

istore_test=# SELECT SUM(count) from event_log where id = 35;
    sum
----------
  50213687
(1 row)

Time: 374,806 ms

Where you can already see the performance benefit.

Which is mostly due to the reduced IO.

SELECT pg_size_pretty(pg_table_size('event_log')) as "without istore", pg_size_pretty(pg_table_size('istore_event_log')) as "with istore";
  without istore | with istore
----------------+-------------
  249 MB         | 87 MB

The following functions and operators apply to both istore and bigistore types.

istore Operators

Operator Description Example Result
istore -> integer get value for key (NULL if not present) '1=>4,2=>5'::istore -> 1 4
istore -> integer[] get values or key (NULL if not present) '1=>4,2=>5'::istore -> Array[1,3] {4,NULL}
istore ? integer does istore contain key? '1=>4,2=>5'::istore ? 2 t
istore ?& integer[] does istore contain all specified keys? '1=>4,2=>5'::istore ?& ARRAY[1,3] f
istore ?| integer[] does istore contain any of the specified keys? '1=>4,2=>5'::istore ?| ARRAY[1,3] t
istore || istore concatenate istores '1=>4, 2=>5'::istore || '3=>4, 2=>7' "1"=>"4", "2"=>"7", "3"=>"4"
istore + istore add value of matching keys (missing key will be treated as 0) '1=>4,2=>5'::istore + '1=>4,3=>6'::istore "1"=>"8", "2"=>"5", "3"=>"6"
istore + integer add right operant to all values '1=>4,2=>5'::istore + 3 "1"=>"7", "2"=>"8"
istore - istore subtract value of matching keys (missing key will be treated as 0) '1=>4,2=>5'::istore - '1=>4,3=>6'::istore "1"=>"0", "2"=>"5", "3"=>"-6"
istore - integer subtract right operant to all values '1=>4,2=>5'::istore - 3 "1"=>"1", "2"=>"2"
istore * istore multiply value of matching keys (missing key will be ignored) '1=>4,2=>5'::istore * '1=>4,3=>6'::istore "1"=>"16"
istore * integer multiply right operant to all values '1=>4,2=>5'::istore * 3 "1"=>"12", "2"=>"15"
istore / istore divide value of matching keys (missing key will be ignored) '1=>4,2=>5'::istore / '1=>4,3=>6'::istore "1"=>"1"
istore / integer divide right operant to all values '1=>4,2=>5'::istore / 3 "1"=>"1", "2"=>"1"
%% istore convert istore to array of alternating keys and values %% '1=>4,2=>5'::istore {1,4,2,5}
%# istore convert istore to two-dimensional key/value array %# '1=>4,2=>5'::istore {{1,4},{2,5}}

istore Functions

Function Return type Description Example Result
exist(istore, integer) boolean does istore contain key? exist('1=>4,5=>10'::istore, 5) t
min_key(istore) integer get the smallest key from an istore (NULL if not present) min_key('1=>4,5=>10'::istore) 1
max_key(istore) integer get the biggest key from an istore (NULL if not present) max_key('1=>4,5=>10'::istore) 5
max_value(istore) integer get the biggest value from an istore (NULL if not present) max_value('1=>4,5=>10'::istore) 10
fetchval(istore, integer) integer get value for key (NULL if not present) fetchval('1=>4,5=>10'::istore, 5) 10
akeys(istore) int[] get istore's keys as an array akeys('1=>3,2=>4') {1,2}
avals(istore) int[] get istore's values as an array avals('1=>3,2=>4') {3,4}
skeys(istore) setof int get istore's keys as a set skeys('1=>3,2=>4') 1
2
svals(istore) setof int get istore's values as a set svals('1=>3,2=>4') 3
4
istore_to_json(istore) json get istore as a json value istore_to_json('1=>4,3=>0,5=>10'::istore) {"1": 4, "3": 0, "5": 10}
compact(istore) istore remove 0 value keys compact('1=>4,3=>0,5=>10'::istore) "1"=>"4", "5"=>"10"
add(istore, istore) istore add value of matching keys (missing key will be treated as 0) add('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"8", "2"=>"5", "3"=>"6"
add(istore, integer) istore add right operant to all values add('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"8", "2"=>"5", "3"=>"6"
subtract(istore, istore) istore subtract value of matching keys (missing key will be treated as 0) subtract('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"0", "2"=>"5", "3"=>"-6"
subtract(istore, integer) istore subtract right operant to all values subtract('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"0", "2"=>"5", "3"=>"-6"
multiply(istore, istore) istore multiply value of matching keys (missing key will be ignored) multiply('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"16"
multiply(istore, integer) istore multiply right operant to all values multiply('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"16"
divide(istore, istore) istore divide value of matching keys (missing key will be ignored) divide('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"1"
divide(istore, integer) istore divide right operant to all values divide('1=>4,2=>5'::istore, '1=>4,3=>6'::istore) "1"=>"1"
istore(integer[]) istore construct an istore from an array by counting elements istore(ARRAY[1,2,1,3,2,2]) "1"=>"2", "2"=>"3", "3"=>"1"
sum_up(istore) bigint sum values of an istore sum_up('1=>4,2=>5'::istore) 9
sum_up(istore, integer) bigint sum values of an istore up to a given key sum_up('1=>4,2=>5,3=>5'::istore,2) 9
istore(integer[], integer[]) istore construct an istore from separate key and value arrays istore(ARRAY[1,2,3], ARRAY[4,5,6]) "1"=>"4", "2"=>"5", "3"=>"6"
fill_gaps(istore, integer, integer) istore fill missing istore keys upto second parameter with third parameter fill_gaps('1=>4,3=>10'::istore,4,2) "0"=>"2", "1"=>"4", "2"=>"2", "3"=>"10", "4"=>"2"
accumulate(istore) istore for each key calculate the rolling sum of values accumulate('1=>4,3=>10'::istore) "1"=>"4", "2"=>"4", "3"=>"14"
accumulate(istore, integer) istore for each key calculate the rolling sum of values upto second parameter accumulate('1=>4,3=>10'::istore, 4) "1"=>"4", "2"=>"4", "3"=>"14", "4"=>"14"
istore_seed(integer, integer, integer) istore create an istore from first to second parameter with third parameter value istore_seed(2, 4, 5) "2"=>"5", "3"=>"5", "4"=>"5"
istore_val_larger(istore, istore) istore merge istores with larger values istore_val_larger('1=>4,2=>5'::istore, '1=>5,3=>6'::istore) "1"=>"5", "2"=>"5", "3"=>"6"
istore_val_smaller(istore, istore) istore merge istores with smaller values istore_val_smaller('1=>4,2=>5'::istore, '1=>5,3=>6'::istore) "1"=>"4", "2"=>"5", "3"=>"6"
each(istore) setof(key int, value int) get istore's keys and values as a set each('1=>4,5=>10'::istore) key | value
----+-------
1 | 4
5 | 10
istore_to_json(istore) integer[] get istore's keys and values as json istore_to_json('1=>4,2=>5'::istore) {"1": 4, "2": 5}
istore_to_array(istore) integer[] get istore's keys and values as an array of alternating keys and values istore_to_array('1=>4,2=>5'::istore) {1,4,2,5}
istore_to_matrix(istore) integer[] get istore's keys and values as a two-dimensional array istore_to_matrix('1=>4,2=>5'::istore) {{1,4},{2,5}}
slice(istore, integer[]) istore extract a subset of an istore slice('1=>4,2=>5'::istore, ARRAY[2]) "2"=>"5"
slice(istore, min integer, max integer) istore extract a subset of an istore where keys are between min and max slice('1=>4,2=>5,3=>6,4=>7'::istore, 2, 3) "2"=>"5","3=>6"
slice_array(istore, integer[]) integer[] extract a subset of an istore slice_array('1=>4,2=>5'::istore, ARRAY[2]) {5}
clamp_below(istore, integer) istore delete k/v pair up to a specified threshold and write their sum clamp_below('1=>4,2=>5,3=>6'::istore, 2) "2"=>"9","3"=>"6"
clamp_above(istore, integer) istore delete k/v pair down to a specified threshold and write their sum clamp_above('1=>4,2=>5,3=>6'::istore, 2) "1"=>"4","2"=>"11"
delete(istore, integer) istore delete pair with matching key delete('1=>4,2=>5'::istore, 2) "1"=>"4"
delete(istore, integer[]) istore delete pair with matching keys delete('1=>4,2=>5'::istore, ARRAY[2]) "1"=>"4"
exists_all(istore, integer[]) boolean does istore contain all specified keys? exists_all('1=>4,2=>5'::istore, ARRAY[2]) t
exists_any(istore, integer[]) boolean does istore contain any of the specified keys? exists_any('1=>4,2=>5'::istore, ARRAY[2]) t
delete(istore, istore) istore delete matching pairs delete('1=>4,2=>5'::istore, '1=>3,2=>5') "1"=>"4"
concat(istore, istore) istore concat two istores concat('1=>4, 2=>5'::istore, '3=>4, 2=>7'::istore) "1"=>"4", "2"=>"7", "3"=>"4"
istore_in_range(istore, integer, integer) boolean do istore values lie within the given (inclusive) range? istore_in_range('-1=>2, 10=>17, 5=>44'::istore, 0, 44) t
istore_less_than(istore, integer) boolean do istore values lie below the given value? istore_less_than('-1=>2, 10=>17, 5=>44'::istore, 44) f
istore_less_than_or_equal(istore, integer) boolean do istore values lie below or equal to the given value? istore_less_than_or_equal('-1=>2, 10=>17, 5=>44'::istore, 44) t
istore_greater_than(istore, integer) boolean do istore values lie above the given value? istore_greater_than('-1=>2, 10=>17, 5=>44'::istore, 2) f
istore_greater_than_or_equa(istore, integer) boolean do istore values lie above or equal to the given value? istore_greater_than_or_equal('-1=>2, 10=>17, 5=>44'::istore, 2) t
istore_floor(istore, integer) istore replace all values lower than the boundary with the boundary value istore_floor('-1=>2, 10=>17, 5=>44'::istore, 20) "-1"=>"20", "10"=>"20", "5"=>"44"
istore_ceiling(istore, integer) istore replace all values greater than the boundary with the boundary value istore_ceiling('-1=>2, 10=>17, 5=>44'::istore, 20) "-1"=>"2", "10"=>"17", "5"=>"20"

istore Aggregate Functions

Function Argument Type(s) Return Type Description
sum(expression) istore, bigistore bigistore sum of expression across all input values
min(expression) istore, bigistore same as argument type merge across all input values by selecting minimum keys value
max(expression) istore, bigistore same as argument type merge across all input values by selecting maximum keys value

Indexes

istore has GIN index support for the ? operators For example:

CREATE INDEX hidx ON testistore USING GIN (i);

Authors

Alex Kliukin [email protected], Berlin, adjust GmbH, Germany

Ildar Musin [email protected], Berlin, adjust GmbH, Germany

Manuel Kniep [email protected], Berlin, adjust GmbH, Germany

Robert Abraham [email protected], Berlin, adjust GmbH, Germany

GIN index support by Emre Hasegeli [email protected], Hamburg, Germany

istore's People

Contributors

alexeyklyukin avatar andreasscherbaum avatar chochkov avatar dependabot[bot] avatar einhverfr avatar ildus avatar m7shapan avatar moktin avatar perikadjust avatar rapimo avatar roa avatar sumerman avatar za-arthur avatar zilder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

istore's Issues

istore precludes parallel queries

There are some aggregates that are still not parallel-safe (namely, isagg). They rely on the AVL-tree as an internal state, which makes it slightly more challenging to implement parallel behavior, however, it should pay off if the aggregate Is the last step to the long table scan that can potentially be parallelized.

Istore multiplication is not very friendly

One can do:

select istore'1 => 10, 2 => 20' * 2;

but not

select 2 * istore'1 => 10, 2 => 20';

They should be equivalent in my opinion and latter is much more readable if used in conjunction with istore() function.

postgres 9.2

Hello!

Are there any plans to support version 9.2?

Thanks,
Ibrahim

build failure with postgresql-12

version 0.1.6 doesn't seem to appreciate pg-12:

src/bigistore.c:580:58: error: unknown type name �FunctionCallInfoData�; did you mean �FunctionCallInfoBaseData�?
  580 | setup_firstcall(FuncCallContext *funcctx, BigIStore *is, FunctionCallInfoData *fcinfo)
      |                                                          ^~~~~~~~~~~~~~~~~~~~
      |                                                          FunctionCallInfoBaseData
src/istore.c:579:55: error: unknown type name �FunctionCallInfoData�; did you mean �FunctionCallInfoBaseData�?
  579 | setup_firstcall(FuncCallContext *funcctx, IStore *is, FunctionCallInfoData *fcinfo)
      |                                                       ^~~~~~~~~~~~~~~~~~~~
      |                                                       FunctionCallInfoBaseData
src/bigistore.c: In function �bigistore_each�:
src/bigistore.c:621:9: warning: implicit declaration of function �setup_firstcall� [-Wimplicit-function-declaration]
  621 |         setup_firstcall(funcctx, is, fcinfo);
      |         ^~~~~~~~~~~~~~~
src/istore.c: In function �istore_each�:
src/istore.c:620:9: warning: implicit declaration of function �setup_firstcall� [-Wimplicit-function-declaration]
  620 |         setup_firstcall(funcctx, is, fcinfo);
      |         ^~~~~~~~~~~~~~~
make: *** [<builtin>: src/bigistore.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [<builtin>: src/istore.o] Error

scount

for the numhstore the array_agg step in statments like

SELECT array_count(array_agg(val)) FROM (VALUES('de'),('us'),('de'),('en'))t(val);
           array_count
---------------------------------
 "de"=>"2", "en"=>"1", "us"=>"1"
(1 row)

seems to be the slowest part.

An aggregate function scount (set count) that counts directly without the memory consuming array_agg step might help and could be faster.

aggregate with floor

We should have an aggregate with a floor that one can sum istores together with a floor value. The idea is to filter out, for example, invalid negative numbers.

Proposed invocation:

sum_floor(istorecol, int)

Example:

GIven the following istores in a column called myval:

 {1 => 3, 2 => -2, 3 => 4 }
 {1 => -3, 2 => 5, 3 => 15}
 {1 => 2, 2 => -3, 3 => -1, 4 => -3}

Then:

 sum_floor(myval, 0)

would generate

 {1 => 5, 2 => 5, 3 => 19}

missing equality operator

there is no = operator for istore / bigistore because of that certain sql features like NULLIF or EXCEPT can not be used

would be nice to have the ability to compare for equality

cistore

our new data type cistore (combined integer store) should save the key and values as integer

SELECT 'de::phone::ios=>25'::cistore;
         cistore
------------------------
 "de::phone::ios"=>25

basically the first byte represents country, the second the device_type and the third byte should be interpreted as os_name

We also want a fourth byte which is a plain integer

SELECT 'de::phone::ios=>25'::cistore;
         cistore
------------------------
 "de::phone::ios::0"=>25

this one is later some cohort place or punchcard hour, whatever we need.

Operator istore - int[]

Hello!
Could you add a new subtract operator?

istore - integer[]

Description:
subtract keys from istore
Example:
'1=>4,2=>5'::istore - '{2,4}'::integer[]
Result:
"1"=>"4"

remove compiler warnings

i get

src/device_type.c:45:1: warning: no previous prototype for function 'device_type_recv' [-Wmissing-prototypes]
device_type_recv(PG_FUNCTION_ARGS)
^
src/device_type.c:55:1: warning: no previous prototype for function 'device_type_send' [-Wmissing-prototypes]
device_type_send(PG_FUNCTION_ARGS)
^
src/device_type.c:148:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
src/device_type.c:168:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
4 warnings generated.
src/istore.c:19:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
src/istore.c:23:1: warning: no previous prototype for function 'istore_sum_up' [-Wmissing-prototypes]
istore_sum_up(PG_FUNCTION_ARGS)
^
src/istore.c:66:1: warning: no previous prototype for function 'is_exist' [-Wmissing-prototypes]
is_exist(PG_FUNCTION_ARGS)
^
src/istore.c:73:5: warning: variable 'key' is used uninitialized whenever switch default is taken
      [-Wsometimes-uninitialized]
    GET_KEYARG_BY_TYPE(in, key);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/istore.h:255:13: note: expanded from macro 'GET_KEYARG_BY_TYPE'
            default:                                          \
            ^~~~~~~
src/istore.c:74:21: note: uninitialized use occurs here
    if (is_find(in, key))
                    ^~~
src/istore.c:69:16: note: initialize the variable 'key' to silence this warning
    int     key;
               ^
                = 0
src/istore.c:83:1: warning: no previous prototype for function 'is_fetchval' [-Wmissing-prototypes]
is_fetchval(PG_FUNCTION_ARGS)
^
src/istore.c:90:5: warning: variable 'key' is used uninitialized whenever switch default is taken
      [-Wsometimes-uninitialized]
    GET_KEYARG_BY_TYPE(in, key);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
src/istore.h:255:13: note: expanded from macro 'GET_KEYARG_BY_TYPE'
            default:                                          \
            ^~~~~~~
src/istore.c:91:29: note: uninitialized use occurs here
    if ((pair = is_find(in, key)) == NULL )
                            ^~~
src/istore.c:86:16: note: initialize the variable 'key' to silence this warning
    int     key;
               ^
                = 0
src/istore.c:99:1: warning: no previous prototype for function 'is_add' [-Wmissing-prototypes]
is_add(PG_FUNCTION_ARGS)
^
src/istore.c:167:1: warning: no previous prototype for function 'is_add_integer' [-Wmissing-prototypes]
is_add_integer(PG_FUNCTION_ARGS)
^
src/istore.c:196:1: warning: no previous prototype for function 'is_subtract' [-Wmissing-prototypes]
is_subtract(PG_FUNCTION_ARGS)
^
src/istore.c:263:1: warning: no previous prototype for function 'is_subtract_integer' [-Wmissing-prototypes]
is_subtract_integer(PG_FUNCTION_ARGS)
^
src/istore.c:292:1: warning: no previous prototype for function 'is_multiply' [-Wmissing-prototypes]
is_multiply(PG_FUNCTION_ARGS)
^
src/istore.c:361:1: warning: no previous prototype for function 'is_multiply_integer' [-Wmissing-prototypes]
is_multiply_integer(PG_FUNCTION_ARGS)
^
src/istore.c:545:1: warning: no previous prototype for function 'istore_from_array' [-Wmissing-prototypes]
istore_from_array(PG_FUNCTION_ARGS)
^
src/istore.c:557:1: warning: no previous prototype for function 'device_istore_from_array' [-Wmissing-prototypes]
device_istore_from_array(PG_FUNCTION_ARGS)
^
src/istore.c:575:1: warning: no previous prototype for function 'country_istore_from_array' [-Wmissing-prototypes]
country_istore_from_array(PG_FUNCTION_ARGS)
^
src/istore.c:593:1: warning: no previous prototype for function 'os_name_istore_from_array' [-Wmissing-prototypes]
os_name_istore_from_array(PG_FUNCTION_ARGS)
^
src/istore.c:654:1: warning: no previous prototype for function 'istore_agg' [-Wmissing-prototypes]
istore_agg(PG_FUNCTION_ARGS)
^
src/istore.c:698:1: warning: no previous prototype for function 'istore_agg_finalfn' [-Wmissing-prototypes]
istore_agg_finalfn(PG_FUNCTION_ARGS)
^
src/istore.c:719:1: warning: no previous prototype for function 'istore_array_add' [-Wmissing-prototypes]
istore_array_add(PG_FUNCTION_ARGS)
^
19 warnings generated.
src/istore_io.c:244:1: warning: no previous prototype for function 'type_istore_to_istore' [-Wmissing-prototypes]
type_istore_to_istore(PG_FUNCTION_ARGS)
^
src/istore_io.c:269:1: warning: no previous prototype for function 'istore_to_device_istore' [-Wmissing-prototypes]
istore_to_device_istore(PG_FUNCTION_ARGS)
^
src/istore_io.c:292:1: warning: no previous prototype for function 'istore_to_country_istore' [-Wmissing-prototypes]
istore_to_country_istore(PG_FUNCTION_ARGS)
^
src/istore_io.c:315:1: warning: no previous prototype for function 'istore_to_os_name_istore' [-Wmissing-prototypes]
istore_to_os_name_istore(PG_FUNCTION_ARGS)
^
src/istore_io.c:338:1: warning: no previous prototype for function 'istore_out' [-Wmissing-prototypes]
istore_out(PG_FUNCTION_ARGS)
^
src/istore_io.c:346:1: warning: no previous prototype for function 'istore_in' [-Wmissing-prototypes]
istore_in(PG_FUNCTION_ARGS)
^
src/istore_io.c:356:1: warning: no previous prototype for function 'istore_recv' [-Wmissing-prototypes]
istore_recv(PG_FUNCTION_ARGS)
^
src/istore_io.c:381:1: warning: no previous prototype for function 'istore_send' [-Wmissing-prototypes]
istore_send(PG_FUNCTION_ARGS)
^
src/istore_io.c:403:1: warning: no previous prototype for function 'cistore_out' [-Wmissing-prototypes]
cistore_out(PG_FUNCTION_ARGS)
^
src/istore_io.c:411:1: warning: no previous prototype for function 'cistore_in' [-Wmissing-prototypes]
cistore_in(PG_FUNCTION_ARGS)
^
src/istore_io.c:421:1: warning: no previous prototype for function 'device_istore_in' [-Wmissing-prototypes]
device_istore_in(PG_FUNCTION_ARGS)
^
src/istore_io.c:431:1: warning: no previous prototype for function 'country_istore_in' [-Wmissing-prototypes]
country_istore_in(PG_FUNCTION_ARGS)
^
src/istore_io.c:441:1: warning: no previous prototype for function 'os_name_istore_in' [-Wmissing-prototypes]
os_name_istore_in(PG_FUNCTION_ARGS)
^
src/istore_io.c:451:1: warning: no previous prototype for function 'cistore_from_types' [-Wmissing-prototypes]
cistore_from_types(PG_FUNCTION_ARGS)
^
src/istore_io.c:486:1: warning: no previous prototype for function 'cistore_cohort_from_types' [-Wmissing-prototypes]
cistore_cohort_from_types(PG_FUNCTION_ARGS)
^
15 warnings generated.
src/os_name.c:31:1: warning: no previous prototype for function 'os_name_recv' [-Wmissing-prototypes]
os_name_recv(PG_FUNCTION_ARGS)
^
src/os_name.c:41:1: warning: no previous prototype for function 'os_name_send' [-Wmissing-prototypes]
os_name_send(PG_FUNCTION_ARGS)
^
src/os_name.c:141:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^

on mac os

potential int overflow in clamp_below

It looks like clamp_below runs into an int overflow:

 SELECT clamp_below('"-3"=>"42", "0"=>"2235078024"'::bigistore,0);
    clamp_below
--------------------
 "0"=>"-2059889230"
(1 row)

istore/src/bigistore.c

Lines 1248 to 1270 in 08ee021

bigistore_clamp_pass(BigIStore *is, int32 clamp_key, int delta_dir)
{
BigIStore * result_is;
BigIStorePair *pairs;
BigIStorePairs creator;
int32 clamp_sum = 0;
int index = 0, count = 0, delta_buflen = 0;
/* short circuit out of the funciton if there is nothing to clamp */
if (delta_dir > 0 && FIRST_PAIR(is, BigIStorePair)->key >= clamp_key)
return is;
if (delta_dir < 0 && LAST_PAIR(is, BigIStorePair)->key <= clamp_key)
return is;
pairs = FIRST_PAIR(is, BigIStorePair);
index = delta_dir > 0 ? 0 : is->len - 1;
while (((delta_dir > 0) && (index < is->len && pairs[index].key <= clamp_key)) ||
((delta_dir < 0) && (index >= 0 && pairs[index].key >= clamp_key)))
{
INTPL(pairs[index].val, clamp_sum, clamp_sum);
delta_buflen += bigis_pair_buf_len(pairs + index);
index += delta_dir, count++;
}

I guess clamp_sum should be an int64 actually

Introduce functions to control the upper and lower boundaries of the values in istore

Namely,
in_range(istore, lower, upper) to return true iff all values in the map are in the given range;
less_than(istore, upper) - returns true iff all values are lower than the given one.
greater_than(istore, lower) - true iff all values are greater the given one.
also, less_or_equal version of all.

In addition,
floor(istore, floor_value) to set all values lower than the floor_value to that value
ceiling(istore, ceiling_value) to set all values higher than the ceiling_value to that value.

That would be kind of coalesce values, together with the functions to check if we need to coalesce (for cases when there are values in the cohorts we need to correct, i.e. negatives).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.