Merge pull request #70 from mcgrawia/add-min-max-functions

Add get_min_item and get_max_item functions for kll float and double sketches
diff --git a/.gitignore b/.gitignore
index 4303c9c..bac564c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
 .project
 .settings/
 
+# CLion project files
+.idea
+
 # Visual Studio Code
 .vscode/
 
diff --git a/sql/datasketches_kll_double_sketch.sql b/sql/datasketches_kll_double_sketch.sql
index 13100f6..884756e 100644
--- a/sql/datasketches_kll_double_sketch.sql
+++ b/sql/datasketches_kll_double_sketch.sql
@@ -118,6 +118,14 @@
     AS '$libdir/datasketches', 'pg_kll_double_sketch_get_n'
     LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
 
+CREATE OR REPLACE FUNCTION kll_double_sketch_get_max_item(kll_double_sketch) RETURNS double precision
+    AS '$libdir/datasketches', 'pg_kll_double_sketch_get_max_item'
+    LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OR REPLACE FUNCTION kll_double_sketch_get_min_item(kll_double_sketch) RETURNS double precision
+    AS '$libdir/datasketches', 'pg_kll_double_sketch_get_min_item'
+    LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
 CREATE OR REPLACE FUNCTION kll_double_sketch_to_string(kll_double_sketch) RETURNS TEXT
     AS '$libdir/datasketches', 'pg_kll_double_sketch_to_string'
     LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
diff --git a/sql/datasketches_kll_float_sketch.sql b/sql/datasketches_kll_float_sketch.sql
index 84126d2..52a7f01 100644
--- a/sql/datasketches_kll_float_sketch.sql
+++ b/sql/datasketches_kll_float_sketch.sql
@@ -71,7 +71,7 @@
     SFUNC = kll_float_sketch_build_agg,
     COMBINEFUNC = kll_float_sketch_combine,
     SERIALFUNC = kll_float_sketch_serialize,
-    DESERIALFUNC = kll_float_sketch_deserialize, 
+    DESERIALFUNC = kll_float_sketch_deserialize,
     FINALFUNC = kll_float_sketch_finalize,
     PARALLEL = SAFE
 );
@@ -81,7 +81,7 @@
     SFUNC = kll_float_sketch_build_agg,
     COMBINEFUNC = kll_float_sketch_combine,
     SERIALFUNC = kll_float_sketch_serialize,
-    DESERIALFUNC = kll_float_sketch_deserialize, 
+    DESERIALFUNC = kll_float_sketch_deserialize,
     FINALFUNC = kll_float_sketch_finalize,
     PARALLEL = SAFE
 );
@@ -91,7 +91,7 @@
     SFUNC = kll_float_sketch_merge_agg,
     COMBINEFUNC = kll_float_sketch_combine,
     SERIALFUNC = kll_float_sketch_serialize,
-    DESERIALFUNC = kll_float_sketch_deserialize, 
+    DESERIALFUNC = kll_float_sketch_deserialize,
     FINALFUNC = kll_float_sketch_finalize,
     PARALLEL = SAFE
 );
@@ -101,7 +101,7 @@
     SFUNC = kll_float_sketch_merge_agg,
     COMBINEFUNC = kll_float_sketch_combine,
     SERIALFUNC = kll_float_sketch_serialize,
-    DESERIALFUNC = kll_float_sketch_deserialize, 
+    DESERIALFUNC = kll_float_sketch_deserialize,
     FINALFUNC = kll_float_sketch_finalize,
     PARALLEL = SAFE
 );
@@ -118,6 +118,14 @@
     AS '$libdir/datasketches', 'pg_kll_float_sketch_get_n'
     LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
 
+CREATE OR REPLACE FUNCTION kll_float_sketch_get_max_item(kll_float_sketch) RETURNS real
+    AS '$libdir/datasketches', 'pg_kll_float_sketch_get_max_item'
+    LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OR REPLACE FUNCTION kll_float_sketch_get_min_item(kll_float_sketch) RETURNS real
+    AS '$libdir/datasketches', 'pg_kll_float_sketch_get_min_item'
+    LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
 CREATE OR REPLACE FUNCTION kll_float_sketch_to_string(kll_float_sketch) RETURNS TEXT
     AS '$libdir/datasketches', 'pg_kll_float_sketch_to_string'
     LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
diff --git a/src/kll_double_sketch_c_adapter.cpp b/src/kll_double_sketch_c_adapter.cpp
index 4aa5306..c883261 100644
--- a/src/kll_double_sketch_c_adapter.cpp
+++ b/src/kll_double_sketch_c_adapter.cpp
@@ -86,6 +86,24 @@
   pg_unreachable();
 }
 
+double kll_double_sketch_get_max_item(const void *sketchptr) {
+    try {
+        return static_cast<const kll_double_sketch *>(sketchptr)->get_max_item();
+    } catch (std::exception &e) {
+        pg_error(e.what());
+    }
+    pg_unreachable();
+}
+
+double kll_double_sketch_get_min_item(const void *sketchptr) {
+    try {
+        return static_cast<const kll_double_sketch *>(sketchptr)->get_min_item();
+    } catch (std::exception &e) {
+        pg_error(e.what());
+    }
+    pg_unreachable();
+}
+
 char* kll_double_sketch_to_string(const void* sketchptr) {
   try {
     auto str = static_cast<const kll_double_sketch*>(sketchptr)->to_string();
diff --git a/src/kll_double_sketch_c_adapter.h b/src/kll_double_sketch_c_adapter.h
index 08d172e..169278d 100644
--- a/src/kll_double_sketch_c_adapter.h
+++ b/src/kll_double_sketch_c_adapter.h
@@ -36,6 +36,8 @@
 double kll_double_sketch_get_rank(const void* sketchptr, double value);
 double kll_double_sketch_get_quantile(const void* sketchptr, double rank);
 unsigned long long kll_double_sketch_get_n(const void* sketchptr);
+double kll_double_sketch_get_max_item(const void* sketchptr);
+double kll_double_sketch_get_min_item(const void* sketchptr);
 char* kll_double_sketch_to_string(const void* sketchptr);
 
 struct ptr_with_size kll_double_sketch_serialize(const void* sketchptr, unsigned header_size);
diff --git a/src/kll_double_sketch_pg_functions.c b/src/kll_double_sketch_pg_functions.c
index 8942a98..5dc686e 100644
--- a/src/kll_double_sketch_pg_functions.c
+++ b/src/kll_double_sketch_pg_functions.c
@@ -35,6 +35,8 @@
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_rank);
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_quantile);
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_n);
+PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_max_item);
+PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_min_item);
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_to_string);
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_pmf);
 PG_FUNCTION_INFO_V1(pg_kll_double_sketch_get_cdf);
@@ -50,6 +52,8 @@
 Datum pg_kll_double_sketch_get_rank(PG_FUNCTION_ARGS);
 Datum pg_kll_double_sketch_get_quantile(PG_FUNCTION_ARGS);
 Datum pg_kll_double_sketch_get_n(PG_FUNCTION_ARGS);
+Datum pg_kll_double_sketch_get_max_item(PG_FUNCTION_ARGS);
+Datum pg_kll_double_sketch_get_min_item(PG_FUNCTION_ARGS);
 Datum pg_kll_double_sketch_to_string(PG_FUNCTION_ARGS);
 Datum pg_kll_double_sketch_get_pmf(PG_FUNCTION_ARGS);
 Datum pg_kll_double_sketch_get_cdf(PG_FUNCTION_ARGS);
@@ -237,6 +241,28 @@
   PG_RETURN_INT64(n);
 }
 
+Datum pg_kll_double_sketch_get_max_item(PG_FUNCTION_ARGS) {
+    const bytea* bytes_in;
+    void* sketchptr;
+    double value;
+    bytes_in = PG_GETARG_BYTEA_P(0);
+    sketchptr = kll_double_sketch_deserialize(VARDATA(bytes_in), VARSIZE(bytes_in) - VARHDRSZ);
+    value = kll_double_sketch_get_max_item(sketchptr);
+    kll_double_sketch_delete(sketchptr);
+    PG_RETURN_FLOAT8(value);
+}
+
+Datum pg_kll_double_sketch_get_min_item(PG_FUNCTION_ARGS) {
+    const bytea* bytes_in;
+    void* sketchptr;
+    double value;
+    bytes_in = PG_GETARG_BYTEA_P(0);
+    sketchptr = kll_double_sketch_deserialize(VARDATA(bytes_in), VARSIZE(bytes_in) - VARHDRSZ);
+    value = kll_double_sketch_get_min_item(sketchptr);
+    kll_double_sketch_delete(sketchptr);
+    PG_RETURN_FLOAT8(value);
+}
+
 Datum pg_kll_double_sketch_to_string(PG_FUNCTION_ARGS) {
   const bytea* bytes_in;
   void* sketchptr;
diff --git a/src/kll_float_sketch_c_adapter.cpp b/src/kll_float_sketch_c_adapter.cpp
index 30a4bdc..bb6a6d5 100644
--- a/src/kll_float_sketch_c_adapter.cpp
+++ b/src/kll_float_sketch_c_adapter.cpp
@@ -86,6 +86,24 @@
   pg_unreachable();
 }
 
+float kll_float_sketch_get_max_item(const void *sketchptr) {
+    try {
+        return static_cast<const kll_float_sketch *>(sketchptr)->get_max_item();
+    } catch (std::exception &e) {
+        pg_error(e.what());
+    }
+    pg_unreachable();
+}
+
+float kll_float_sketch_get_min_item(const void *sketchptr) {
+    try {
+        return static_cast<const kll_float_sketch *>(sketchptr)->get_min_item();
+    } catch (std::exception &e) {
+        pg_error(e.what());
+    }
+    pg_unreachable();
+}
+
 char* kll_float_sketch_to_string(const void* sketchptr) {
   try {
     auto str = static_cast<const kll_float_sketch*>(sketchptr)->to_string();
diff --git a/src/kll_float_sketch_c_adapter.h b/src/kll_float_sketch_c_adapter.h
index f175906..e54cc5c 100644
--- a/src/kll_float_sketch_c_adapter.h
+++ b/src/kll_float_sketch_c_adapter.h
@@ -36,6 +36,8 @@
 double kll_float_sketch_get_rank(const void* sketchptr, float value);
 float kll_float_sketch_get_quantile(const void* sketchptr, double rank);
 unsigned long long kll_float_sketch_get_n(const void* sketchptr);
+float kll_float_sketch_get_max_item(const void* sketchptr);
+float kll_float_sketch_get_min_item(const void* sketchptr);
 char* kll_float_sketch_to_string(const void* sketchptr);
 
 struct ptr_with_size kll_float_sketch_serialize(const void* sketchptr, unsigned header_size);
diff --git a/src/kll_float_sketch_pg_functions.c b/src/kll_float_sketch_pg_functions.c
index 8714147..83d4936 100644
--- a/src/kll_float_sketch_pg_functions.c
+++ b/src/kll_float_sketch_pg_functions.c
@@ -35,6 +35,8 @@
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_rank);
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_quantile);
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_n);
+PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_max_item);
+PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_min_item);
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_to_string);
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_pmf);
 PG_FUNCTION_INFO_V1(pg_kll_float_sketch_get_cdf);
@@ -50,6 +52,8 @@
 Datum pg_kll_float_sketch_get_rank(PG_FUNCTION_ARGS);
 Datum pg_kll_float_sketch_get_quantile(PG_FUNCTION_ARGS);
 Datum pg_kll_float_sketch_get_n(PG_FUNCTION_ARGS);
+Datum pg_kll_float_sketch_get_max_item(PG_FUNCTION_ARGS);
+Datum pg_kll_float_sketch_get_min_item(PG_FUNCTION_ARGS);
 Datum pg_kll_float_sketch_to_string(PG_FUNCTION_ARGS);
 Datum pg_kll_float_sketch_get_pmf(PG_FUNCTION_ARGS);
 Datum pg_kll_float_sketch_get_cdf(PG_FUNCTION_ARGS);
@@ -237,6 +241,28 @@
   PG_RETURN_INT64(n);
 }
 
+Datum pg_kll_float_sketch_get_max_item(PG_FUNCTION_ARGS) {
+    const bytea* bytes_in;
+    void* sketchptr;
+    float value;
+    bytes_in = PG_GETARG_BYTEA_P(0);
+    sketchptr = kll_float_sketch_deserialize(VARDATA(bytes_in), VARSIZE(bytes_in) - VARHDRSZ);
+    value = kll_float_sketch_get_max_item(sketchptr);
+    kll_float_sketch_delete(sketchptr);
+    PG_RETURN_FLOAT4(value);
+}
+
+Datum pg_kll_float_sketch_get_min_item(PG_FUNCTION_ARGS) {
+    const bytea* bytes_in;
+    void* sketchptr;
+    float value;
+    bytes_in = PG_GETARG_BYTEA_P(0);
+    sketchptr = kll_float_sketch_deserialize(VARDATA(bytes_in), VARSIZE(bytes_in) - VARHDRSZ);
+    value = kll_float_sketch_get_min_item(sketchptr);
+    kll_float_sketch_delete(sketchptr);
+    PG_RETURN_FLOAT4(value);
+}
+
 Datum pg_kll_float_sketch_to_string(PG_FUNCTION_ARGS) {
   const bytea* bytes_in;
   void* sketchptr;
diff --git a/test/kll_double_sketch_test.sql b/test/kll_double_sketch_test.sql
index ab9fbd7..0f5b5f7 100644
--- a/test/kll_double_sketch_test.sql
+++ b/test/kll_double_sketch_test.sql
@@ -17,6 +17,8 @@
 ;
 
 -- get min and max values
+select kll_double_sketch_get_min_item(sketch) as min_item from kll_sketch_test;
+select kll_double_sketch_get_max_item(sketch) as max_item from kll_sketch_test;
 select kll_double_sketch_get_quantiles(sketch, array[0, 1]) as min_max from kll_sketch_test;
 select kll_double_sketch_to_string(sketch) from kll_sketch_test;
 
diff --git a/test/kll_float_sketch_test.sql b/test/kll_float_sketch_test.sql
index e36ee46..a4ecc3a 100644
--- a/test/kll_float_sketch_test.sql
+++ b/test/kll_float_sketch_test.sql
@@ -17,6 +17,8 @@
 ;
 
 -- get min and max values
+select kll_float_sketch_get_min_item(sketch) as min_item from kll_sketch_test;
+select kll_float_sketch_get_max_item(sketch) as max_item from kll_sketch_test;
 select kll_float_sketch_get_quantiles(sketch, array[0, 1]) as min_max from kll_sketch_test;
 select kll_float_sketch_to_string(sketch) from kll_sketch_test;