Code

CData: Use errdetail() rather than errhint() to report details ;-)
[postrr.git] / src / cdata.c
index 6d202e20da6f525c63c470038f5015edcdd1c001..2630e733d35d10200e9938adc5082ff6bc200ea2 100644 (file)
@@ -78,6 +78,10 @@ PG_FUNCTION_INFO_V1(cdata_typmodin);
 PG_FUNCTION_INFO_V1(cdata_typmodout);
 
 PG_FUNCTION_INFO_V1(cdata_to_cdata);
+PG_FUNCTION_INFO_V1(int32_to_cdata);
+PG_FUNCTION_INFO_V1(cdata_to_float8);
+
+PG_FUNCTION_INFO_V1(cdata_update);
 
 /*
  * public API
@@ -156,9 +160,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)
@@ -185,8 +193,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);
@@ -296,5 +305,109 @@ cdata_to_cdata(PG_FUNCTION_ARGS)
        PG_RETURN_CDATA_P(data);
 } /* cdata_to_cdata */
 
+Datum
+int32_to_cdata(PG_FUNCTION_ARGS)
+{
+       int32 i_val;
+       int32 typmod;
+
+       cdata_t *data;
+
+       if (PG_NARGS() != 3)
+               ereport(ERROR, (
+                                       errmsg("int32_to_cdata() expects three arguments"),
+                                       errhint("Usage: int32_to_cdata"
+                                               "(integer, typmod, is_explicit)")
+                               ));
+
+       i_val  = PG_GETARG_INT32(0);
+       typmod = PG_GETARG_INT32(1);
+
+       data = (cdata_t *)palloc0(sizeof(*data));
+
+       data->value     = (float8)i_val;
+       data->undef_num = 0;
+       data->val_num   = 1;
+
+       if (typmod >= 0)
+               data->cf = typmod;
+       else
+               data->cf = CF_AVG;
+
+       PG_RETURN_CDATA_P(data);
+} /* int32_to_cdata */
+
+Datum
+cdata_to_float8(PG_FUNCTION_ARGS)
+{
+       cdata_t *data;
+
+       if (PG_NARGS() != 1)
+               ereport(ERROR, (
+                                       errmsg("cdata_to_float8() expects one argument"),
+                                       errhint("Usage: cdata_to_float8(cdata)")
+                               ));
+
+       data = PG_GETARG_CDATA_P(0);
+       PG_RETURN_FLOAT8(data->value);
+} /* cdata_to_float8 */
+
+Datum
+cdata_update(PG_FUNCTION_ARGS)
+{
+       cdata_t *data;
+       cdata_t *update;
+
+       if (PG_NARGS() != 2)
+               ereport(ERROR, (
+                                       errmsg("cdata_update() expects two arguments"),
+                                       errhint("Usage: cdata_update(cdata, cdata)")
+                               ));
+
+       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),
+                                       errmsg("invalid update value: incompatible "
+                                               "consolidation function")
+                               ));
+
+       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);
+                       break;
+               case CF_MIN:
+                       data->value = (data->value <= update->value)
+                               ? data->value : update->value;
+                       break;
+               case CF_MAX:
+                       data->value = (data->value >= update->value)
+                               ? data->value : update->value;
+                       break;
+               default:
+                       ereport(ERROR, (
+                                               errcode(ERRCODE_DATA_CORRUPTED),
+                                               errmsg("unknown consolidation function %d",
+                                                       data->cf)
+                                       ));
+                       break;
+       }
+
+       data->undef_num += update->undef_num;
+       data->val_num   += update->val_num;
+       PG_RETURN_CDATA_P(data);
+} /* cdata_update */
+
 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */