X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcdata.c;h=2630e733d35d10200e9938adc5082ff6bc200ea2;hb=92e8ddbbc721025619a0b15a963af7efab5acfde;hp=076b037bbe903d4c73b43528018b21288b6c1486;hpb=c03e5a891c8221d4283500de8e6e865770ddae30;p=postrr.git diff --git a/src/cdata.c b/src/cdata.c index 076b037..2630e73 100644 --- a/src/cdata.c +++ b/src/cdata.c @@ -32,19 +32,35 @@ #include "postrr.h" #include +#include #include #include /* Postgres utilities */ +#include #include +enum { + CF_AVG = 0, + CF_MIN = 1, + CF_MAX = 2 +}; + +#define CF_TO_STR(cf) \ + (((cf) == CF_AVG) \ + ? "AVG" \ + : ((cf) == CF_MIN) \ + ? "MIN" \ + : ((cf) == CF_MAX) \ + ? "MAX" : "UNKNOWN") + /* * data type */ struct cdata { - double value; + float8 value; int32 undef_num; int32 val_num; int32 cf; @@ -62,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 @@ -140,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) @@ -169,12 +193,221 @@ 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); } /* cdata_out */ +Datum +cdata_typmodin(PG_FUNCTION_ARGS) +{ + ArrayType *tm_array; + + Datum *elem_values; + int n; + char *cf_str; + int32 typmod = CF_AVG; + + if (PG_NARGS() != 1) + ereport(ERROR, ( + errmsg("cdata_typmodin() expects one argument"), + errhint("Usage: cdata_typmodin(array)") + )); + + tm_array = PG_GETARG_ARRAYTYPE_P(0); + + if (ARR_ELEMTYPE(tm_array) != CSTRINGOID) + ereport(ERROR, ( + errcode(ERRCODE_ARRAY_ELEMENT_ERROR), + errmsg("typmod array must be type cstring[]") + )); + + if (ARR_NDIM(tm_array) != 1) + ereport(ERROR, ( + errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), + errmsg("typmod array must be one-dimensional") + )); + + deconstruct_array(tm_array, CSTRINGOID, + /* elmlen = */ -2, /* elmbyval = */ false, /* elmalign = */ 'c', + &elem_values, /* nullsp = */ NULL, &n); + + if (n != 1) + ereport(ERROR, ( + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cdata typmod array must have one element") + )); + + cf_str = DatumGetCString(elem_values[0]); + if (! strcasecmp(cf_str, "AVG")) + typmod = CF_AVG; + else if (! strcasecmp(cf_str, "MIN")) + typmod = CF_MIN; + else if (! strcasecmp(cf_str, "MAX")) + typmod = CF_MAX; + else + ereport(ERROR, ( + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid cdata typmod: %s", cf_str) + )); + + PG_RETURN_INT32(typmod); +} /* cdata_typmodin */ + +Datum +cdata_typmodout(PG_FUNCTION_ARGS) +{ + int32 typmod; + char tm_str[32]; + char *result; + + if (PG_NARGS() != 1) + ereport(ERROR, ( + errmsg("cdata_typmodout() expects one argument"), + errhint("Usage: cdata_typmodout(typmod)") + )); + + typmod = PG_GETARG_INT32(0); + snprintf(tm_str, sizeof(tm_str), "('%s')", CF_TO_STR(typmod)); + tm_str[sizeof(tm_str) - 1] = '\0'; + result = pstrdup(tm_str); + PG_RETURN_CSTRING(result); +} /* cdata_typmodout */ + +Datum +cdata_to_cdata(PG_FUNCTION_ARGS) +{ + cdata_t *data; + int32 typmod; + + if (PG_NARGS() != 3) + ereport(ERROR, ( + errmsg("cdata_to_cdata() " + "expects three arguments"), + errhint("Usage: cdata_to_cdata" + "(cdata, typmod, is_explicit)") + )); + + data = PG_GETARG_CDATA_P(0); + typmod = PG_GETARG_INT32(1); + + if ((data->cf >= 0) && (data->cf != typmod) && (data->val_num > 1)) + ereport(ERROR, ( + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid cast: cannot cast cdata " + "with different typmod (yet)") + )); + + data->cf = typmod; + 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 : */