From 432bf5c5ed16fcd5a1b6a305cfe93715384a8bcf Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Fri, 1 Aug 2014 08:59:50 +0200 Subject: [PATCH] data: Support some arithmetic expressions on mismatching types. The following cases are now supported: - or - or
or or Think of having a time unit like seconds. It's perfectly fine to multiply with or divide seconds by a number. However, since we don't have any type having the unit Hertz, we cannot support numbers divided by . --- src/core/data.c | 97 +++++++++++++++++++++++++++++++++++++---- src/include/core/data.h | 11 +++-- t/unit/core/data_test.c | 45 +++++++++++++++++++ 3 files changed, 142 insertions(+), 11 deletions(-) diff --git a/src/core/data.c b/src/core/data.c index cdafac3..fc646f0 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -208,13 +208,12 @@ int sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) { - if (d1->type != d2->type) - return -1; - switch (op) { case SDB_DATA_CONCAT: return data_concat(d1, d2, res); case SDB_DATA_ADD: + if (d1->type != d2->type) + return -1; switch (d1->type) { case SDB_TYPE_INTEGER: res->data.integer = d1->data.integer + d2->data.integer; @@ -230,6 +229,8 @@ sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, } break; case SDB_DATA_SUB: + if (d1->type != d2->type) + return -1; switch (d1->type) { case SDB_TYPE_INTEGER: res->data.integer = d1->data.integer - d2->data.integer; @@ -247,13 +248,51 @@ sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, case SDB_DATA_MUL: switch (d1->type) { case SDB_TYPE_INTEGER: - res->data.integer = d1->data.integer * d2->data.integer; + if (d2->type == SDB_TYPE_INTEGER) + res->data.integer = d1->data.integer + * d2->data.integer; + else if (d2->type == SDB_TYPE_DATETIME) { + res->data.datetime = (sdb_time_t)d1->data.integer + * d2->data.datetime; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else + return -1; break; case SDB_TYPE_DECIMAL: - res->data.decimal = d1->data.decimal * d2->data.decimal; + if (d2->type == SDB_TYPE_DECIMAL) + res->data.decimal = d1->data.decimal + * d2->data.decimal; + else if (d2->type == SDB_TYPE_DATETIME) { + double tmp = d1->data.decimal + * (double)d2->data.datetime; + res->data.datetime = (sdb_time_t)tmp; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else + return -1; break; case SDB_TYPE_DATETIME: - res->data.datetime = d1->data.datetime * d2->data.datetime; + if (d2->type == SDB_TYPE_DATETIME) + res->data.datetime = d1->data.datetime + * d2->data.datetime; + else if (d2->type == SDB_TYPE_INTEGER) { + res->data.datetime = d1->data.datetime + * (sdb_time_t)d2->data.integer; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else if (d2->type == SDB_TYPE_DECIMAL) { + double tmp = (double)d1->data.datetime + * d2->data.decimal; + res->data.datetime = (sdb_time_t)tmp; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else + return -1; break; default: return -1; @@ -262,13 +301,34 @@ sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, case SDB_DATA_DIV: switch (d1->type) { case SDB_TYPE_INTEGER: + if (d2->type != SDB_TYPE_INTEGER) + return -1; res->data.integer = d1->data.integer / d2->data.integer; break; case SDB_TYPE_DECIMAL: + if (d2->type != SDB_TYPE_DECIMAL) + return -1; res->data.decimal = d1->data.decimal / d2->data.decimal; break; case SDB_TYPE_DATETIME: - res->data.datetime = d1->data.datetime / d2->data.datetime; + if (d2->type == SDB_TYPE_DATETIME) + res->data.datetime = d1->data.datetime + / d2->data.datetime; + else if (d2->type == SDB_TYPE_INTEGER) { + res->data.datetime = d1->data.datetime + / (sdb_time_t)d2->data.integer; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else if (d2->type == SDB_TYPE_DECIMAL) { + double tmp = (double)d1->data.datetime + / d2->data.decimal; + res->data.datetime = (sdb_time_t)tmp; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else + return -1; break; default: return -1; @@ -277,13 +337,34 @@ sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, case SDB_DATA_MOD: switch (d1->type) { case SDB_TYPE_INTEGER: + if (d2->type != SDB_TYPE_INTEGER) + return -1; res->data.integer = d1->data.integer % d2->data.integer; break; case SDB_TYPE_DECIMAL: + if (d2->type != SDB_TYPE_DECIMAL) + return -1; res->data.decimal = fmod(d1->data.decimal, d2->data.decimal); break; case SDB_TYPE_DATETIME: - res->data.datetime = d1->data.datetime % d2->data.datetime; + if (d2->type == SDB_TYPE_DATETIME) + res->data.datetime = d1->data.datetime + % d2->data.datetime; + else if (d2->type == SDB_TYPE_INTEGER) { + res->data.datetime = d1->data.datetime + % (sdb_time_t)d2->data.integer; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else if (d2->type == SDB_TYPE_DECIMAL) { + double tmp = fmod((double)d1->data.datetime, + d2->data.decimal); + res->data.datetime = (sdb_time_t)tmp; + res->type = SDB_TYPE_DATETIME; + return 0; + } + else + return -1; break; default: return -1; diff --git a/src/include/core/data.h b/src/include/core/data.h index 2e9b90b..8f9b282 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -143,9 +143,14 @@ enum { /* * sdb_data_expr_eval: - * Evaluate a simple arithmetic expression on two data points. The data-type - * of d1 and d2 have to be the same. String and binary data only support - * concatenation and all other data types only support the other operators. + * Evaluate a simple arithmetic expression on two data points. String and + * binary data only support concatenation and all other data types only + * support the other operators. + * + * The data-types of d1 and d2 have to be the same, except for the following + * cases: + * - or + * - or
or or * * Returns: * - 0 on success diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index 0fd61a5..606eae5 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -421,6 +421,51 @@ START_TEST(test_expr_eval) { .binary = { 6, (unsigned char *)"a\0ab\0b" } }, }, }, + /* supported type-mismatches */ + { + /* int * datetime */ + { SDB_TYPE_INTEGER, { .integer = 20 } }, + { SDB_TYPE_DATETIME, { .datetime = 2 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + { SDB_TYPE_DATETIME, { .datetime = 40 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + SDB_DATA_INIT, + }, + { + /* datetime * int, datetime / int, datetime % int */ + { SDB_TYPE_DATETIME, { .datetime = 20 } }, + { SDB_TYPE_INTEGER, { .integer = 2 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + { SDB_TYPE_DATETIME, { .datetime = 40 } }, + { SDB_TYPE_DATETIME, { .datetime = 10 } }, + { SDB_TYPE_DATETIME, { .datetime = 0 } }, + SDB_DATA_INIT, + }, + { + /* float * datetime */ + { SDB_TYPE_DECIMAL, { .decimal = 20.0 } }, + { SDB_TYPE_DATETIME, { .datetime = 2 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + { SDB_TYPE_DATETIME, { .datetime = 40 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + SDB_DATA_INIT, + }, + { + /* datetime * float, datetime / float, datetime % float */ + { SDB_TYPE_DATETIME, { .datetime = 20 } }, + { SDB_TYPE_DECIMAL, { .decimal = 2.0 } }, + SDB_DATA_INIT, + SDB_DATA_INIT, + { SDB_TYPE_DATETIME, { .datetime = 40 } }, + { SDB_TYPE_DATETIME, { .datetime = 10 } }, + { SDB_TYPE_DATETIME, { .datetime = 0 } }, + SDB_DATA_INIT, + }, }; size_t i; -- 2.30.2