Code

CData: Added support for undefined values.
[postrr.git] / src / cdata.c
index 03fefbc6c510f45556c76237472c1139895e7365..418ec0afa2fe42f3068584cb0551964b70527f0e 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <math.h>
 
 #include <postgres.h>
 #include <fmgr.h>
@@ -153,6 +154,10 @@ cdata_in(PG_FUNCTION_ARGS)
        data->value   = strtod(val_str, &endptr);
        data->val_num = 1;
 
+       if (isnan(data->value)) {
+               data->undef_num = 1;
+       }
+
        if ((endptr == val_str) || errno)
                ereport(ERROR, (
                                        errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
@@ -160,9 +165,13 @@ cdata_in(PG_FUNCTION_ARGS)
                                ));
 
        while ((*endptr != '\0') && isspace((int)*endptr))
+               ++endptr;
+
+       if (*endptr != '\0')
                ereport(ERROR, (
                                        errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
-                                       errmsg("invalid input syntax for cdata: \"%s\"", orig)
+                                       errmsg("invalid input syntax for cdata: \"%s\"", orig),
+                                       errdetail("garbage found after number: \"%s\"", endptr)
                                ));
 
        if (typmod > 0)
@@ -189,8 +198,9 @@ cdata_out(PG_FUNCTION_ARGS)
 
        data = PG_GETARG_CDATA_P(0);
 
-       snprintf(cd_str, sizeof(cd_str), "%g (U:%i/%i)",
-                       data->value, data->undef_num, data->val_num);
+       snprintf(cd_str, sizeof(cd_str), "%g (%s U:%i/%i)",
+                       data->value, CF_TO_STR(data->cf),
+                       data->undef_num, data->val_num);
 
        result = pstrdup(cd_str);
        PG_RETURN_CSTRING(result);
@@ -353,6 +363,12 @@ cdata_update(PG_FUNCTION_ARGS)
        cdata_t *data;
        cdata_t *update;
 
+       float8 value;
+       float8 u_value;
+
+       int32 val_num;
+       int32 u_val_num;
+
        if (PG_NARGS() != 2)
                ereport(ERROR, (
                                        errmsg("cdata_update() expects two arguments"),
@@ -362,6 +378,12 @@ cdata_update(PG_FUNCTION_ARGS)
        data   = PG_GETARG_CDATA_P(0);
        update = PG_GETARG_CDATA_P(1);
 
+       if (! data)
+               PG_RETURN_CDATA_P(update);
+
+       if (! update)
+               PG_RETURN_CDATA_P(data);
+
        if ((data->cf != update->cf) && (update->val_num > 1))
                ereport(ERROR, (
                                        errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -369,20 +391,30 @@ cdata_update(PG_FUNCTION_ARGS)
                                                "consolidation function")
                                ));
 
+       value     = data->value;
+       u_value   = update->value;
+
+       val_num   = data->val_num - data->undef_num;
+       u_val_num = update->val_num - update->undef_num;
+
+       data->undef_num += update->undef_num;
+       data->val_num   += update->val_num;
+
+       if (isnan(value) || isnan(u_value)) {
+               data->value = isnan(value) ? u_value : value;
+               PG_RETURN_CDATA_P(data);
+       }
+
        switch (data->cf) {
                case CF_AVG:
-                       data->value = (data->value * (data->val_num - data->undef_num))
-                               + (update->value * (update->val_num - update->undef_num));
-                       data->value /= (data->val_num - data->undef_num)
-                                       +  (update->val_num - update->undef_num);
+                       data->value = ((value * val_num) + (u_value * u_val_num))
+                               / (val_num + u_val_num);
                        break;
                case CF_MIN:
-                       data->value = (data->value <= update->value)
-                               ? data->value : update->value;
+                       data->value = (value < u_value) ? value : u_value;
                        break;
                case CF_MAX:
-                       data->value = (data->value >= update->value)
-                               ? data->value : update->value;
+                       data->value = (value >= u_value) ? value : u_value;
                        break;
                default:
                        ereport(ERROR, (
@@ -392,9 +424,6 @@ cdata_update(PG_FUNCTION_ARGS)
                                        ));
                        break;
        }
-
-       data->undef_num += update->undef_num;
-       data->val_num   += update->val_num;
        PG_RETURN_CDATA_P(data);
 } /* cdata_update */