From: Sebastian Harl Date: Sun, 19 Oct 2014 12:56:38 +0000 (+0200) Subject: data: Added explicit NULL values. X-Git-Tag: sysdb-0.6.0~102 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=b0e3b4920d34fcf9a70671bc1c424384bd388a2b;p=sysdb.git data: Added explicit NULL values. … and let all expressions involving NULL values to return NULL. --- diff --git a/src/core/data.c b/src/core/data.c index 4840736..f489367 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -34,6 +34,8 @@ #include "core/data.h" #include "utils/error.h" +#include + #include #include @@ -200,21 +202,17 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) else return -1; - if (s1 && s2) { - new = malloc(len1 + len2 + 1); - if (! new) - return -1; + assert(s1 && s2); - if (len1) - memcpy(new, s1, len1); - if (len2) - memcpy(new + len1, s2, len2); - new[len1 + len2] = '\0'; - } - else { - len1 = len2 = 0; - new = NULL; - } + new = malloc(len1 + len2 + 1); + if (! new) + return -1; + + if (len1) + memcpy(new, s1, len1); + if (len2) + memcpy(new + len1, s2, len2); + new[len1 + len2] = '\0'; res->type = d1->type; if (res->type == SDB_TYPE_STRING) { @@ -231,6 +229,8 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) * public API */ +const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT; + int sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src) { @@ -391,6 +391,8 @@ sdb_data_isnull(const sdb_data_t *datum) { if (! datum) return 1; + if (datum->type == SDB_TYPE_NULL) + return 1; if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string)) return 1; if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum)) @@ -424,6 +426,10 @@ sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, { if ((! d1) || (! d2) || (! res)) return -1; + if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) { + *res = SDB_DATA_NULL; + return 0; + } switch (op) { case SDB_DATA_CONCAT: return data_concat(d1, d2, res); diff --git a/src/include/core/data.h b/src/include/core/data.h index ffddf97..514c4d5 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -41,7 +41,8 @@ extern "C" { #endif enum { - SDB_TYPE_INTEGER = 1, + SDB_TYPE_NULL = 0, + SDB_TYPE_INTEGER, SDB_TYPE_DECIMAL, SDB_TYPE_STRING, SDB_TYPE_DATETIME, @@ -78,7 +79,9 @@ typedef struct { } re; /* SDB_TYPE_REGEX */ } data; } sdb_data_t; -#define SDB_DATA_INIT { 0, { .integer = 0 } } +#define SDB_DATA_INIT { SDB_TYPE_NULL, { .integer = 0 } } + +extern const sdb_data_t SDB_DATA_NULL; /* * sdb_data_copy: @@ -135,7 +138,8 @@ sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2); /* * sdb_data_isnull: * Determine whether a datum is NULL. A datum is considered to be NULL if - * either datum is NULL or if the string or binary datum is NULL. + * either datum is NULL or if the type is SDB_TYPE_NULL or if the string or + * binary datum is NULL. */ _Bool sdb_data_isnull(const sdb_data_t *datum); @@ -179,6 +183,8 @@ sdb_data_parse_op(const char *op); * support the other operators. The result may be allocated dynamically and * has to be freed by the caller (using sdb_data_free_datum). * + * If any of the data points is a NULL value, the result is also NULL. + * * The data-types of d1 and d2 have to be the same, except for the following * cases: * - or diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index 2336c5e..9c736d3 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -656,6 +656,8 @@ END_TEST START_TEST(test_expr_eval) { + sdb_data_t err = { -1, { .integer = 0 } }; + struct { sdb_data_t d1; sdb_data_t d2; @@ -674,7 +676,7 @@ START_TEST(test_expr_eval) { SDB_TYPE_INTEGER, { .integer = 221417 } }, { SDB_TYPE_INTEGER, { .integer = 100 } }, { SDB_TYPE_INTEGER, { .integer = 11 } }, - SDB_DATA_INIT, + err, }, { { SDB_TYPE_DECIMAL, { .decimal = 35.0 } }, @@ -684,46 +686,46 @@ START_TEST(test_expr_eval) { SDB_TYPE_DECIMAL, { .decimal = 612.5 } }, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } }, { SDB_TYPE_DECIMAL, { .decimal = 0.0 } }, - SDB_DATA_INIT, + err, }, { { SDB_TYPE_STRING, { .string = NULL } }, { SDB_TYPE_STRING, { .string = "" } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_STRING, { .string = NULL } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { SDB_TYPE_STRING, { .string = NULL } }, { SDB_TYPE_STRING, { .string = NULL } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_STRING, { .string = NULL } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { SDB_TYPE_STRING, { .string = "" } }, { SDB_TYPE_STRING, { .string = NULL } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_STRING, { .string = NULL } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { SDB_TYPE_STRING, { .string = "a" } }, { SDB_TYPE_STRING, { .string = "b" } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, + err, + err, + err, { SDB_TYPE_STRING, { .string = "ab" } }, }, { @@ -734,37 +736,37 @@ START_TEST(test_expr_eval) { SDB_TYPE_DATETIME, { .datetime = 221957403521 } }, { SDB_TYPE_DATETIME, { .datetime = 10001 } }, { SDB_TYPE_DATETIME, { .datetime = 0 } }, - SDB_DATA_INIT, + err, }, { { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - { SDB_TYPE_BINARY, { .binary = { 0, NULL } } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, { { @@ -775,11 +777,11 @@ START_TEST(test_expr_eval) SDB_TYPE_BINARY, { .binary = { 3, (unsigned char *)"b\0b" } }, }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, + err, + err, + err, { SDB_TYPE_BINARY, { .binary = { 6, (unsigned char *)"a\0ab\0b" } }, @@ -788,57 +790,187 @@ START_TEST(test_expr_eval) { { SDB_TYPE_REGEX, { .re = { ".", empty_re } } }, { SDB_TYPE_REGEX, { .re = { ".", empty_re } } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, + err, + err, + err, + err, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_INTEGER, { .integer = 42 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_INTEGER, { .integer = 42 } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_DECIMAL, { .decimal = 47.11 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_DECIMAL, { .decimal = 47.11 } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_STRING, { .string = "47.11" } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_STRING, { .string = "47.11" } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_DATETIME, { .datetime = 4711 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_DATETIME, { .datetime = 4711 } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_BINARY, { .binary = { 1, (unsigned char *)"a" } } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_NULL, { .integer = 0 } }, + { SDB_TYPE_REGEX, { .re = { ".", empty_re } } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + }, + { + { SDB_TYPE_REGEX, { .re = { ".", empty_re } } }, + { SDB_TYPE_NULL, { .integer = 0 } }, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, + SDB_DATA_NULL, }, /* supported type-mismatches */ { /* int * datetime */ { SDB_TYPE_INTEGER, { .integer = 20 } }, { SDB_TYPE_DATETIME, { .datetime = 2 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, { SDB_TYPE_DATETIME, { .datetime = 40 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, + err, }, { /* datetime * int, datetime / int, datetime % int */ { SDB_TYPE_DATETIME, { .datetime = 20 } }, { SDB_TYPE_INTEGER, { .integer = 2 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, { SDB_TYPE_DATETIME, { .datetime = 40 } }, { SDB_TYPE_DATETIME, { .datetime = 10 } }, { SDB_TYPE_DATETIME, { .datetime = 0 } }, - SDB_DATA_INIT, + err, }, { /* float * datetime */ { SDB_TYPE_DECIMAL, { .decimal = 20.0 } }, { SDB_TYPE_DATETIME, { .datetime = 2 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, { SDB_TYPE_DATETIME, { .datetime = 40 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, + err, }, { /* datetime * float, datetime / float, datetime % float */ { SDB_TYPE_DATETIME, { .datetime = 20 } }, { SDB_TYPE_DECIMAL, { .decimal = 2.0 } }, - SDB_DATA_INIT, - SDB_DATA_INIT, + err, + err, { SDB_TYPE_DATETIME, { .datetime = 40 } }, { SDB_TYPE_DATETIME, { .datetime = 10 } }, { SDB_TYPE_DATETIME, { .datetime = 0 } }, - SDB_DATA_INIT, + err, }, }; @@ -870,13 +1002,22 @@ START_TEST(test_expr_eval) check = sdb_data_expr_eval(tests[j].op, &golden_data[i].d1, &golden_data[i].d2, &res); - fail_unless((check == 0) == (tests[j].expected.type != 0), + fail_unless((check == 0) == (tests[j].expected.type != -1), "sdb_data_expr_eval(%s, %s, %s) = %d; expected: %d", SDB_DATA_OP_TO_STRING(tests[j].op), d1_str, d2_str, check, - tests[j].expected.type == 0 ? -1 : 0); - if (tests[j].expected.type == 0) + tests[j].expected.type == -1 ? -1 : 0); + if (tests[j].expected.type == -1) continue; + if (tests[j].expected.type == SDB_TYPE_NULL) { + fail_unless(res.type == SDB_TYPE_NULL, + "sdb_data_expr_eval(%s, %s, %s) evaluated to " + "type %d; expected: SDB_TYPE_NULL", + SDB_DATA_OP_TO_STRING(tests[j].op), + d1_str, d2_str, res.type); + continue; + } + check = sdb_data_cmp(&res, &tests[j].expected); if (check != 0) { char res_str[64] = "", expected_str[64] = ""; @@ -884,9 +1025,11 @@ START_TEST(test_expr_eval) SDB_DOUBLE_QUOTED); sdb_data_format(&tests[j].expected, expected_str, sizeof(expected_str), SDB_DOUBLE_QUOTED); - fail("sdb_data_expr_eval(%s, %s, %s) evaluated to %s; " - "expected: %s", SDB_DATA_OP_TO_STRING(tests[j].op), - d1_str, d2_str, res_str, expected_str); + fail("sdb_data_expr_eval(%s, %s, %s) evaluated to %s " + "(type %d); expected: %s (type %d)", + SDB_DATA_OP_TO_STRING(tests[j].op), + d1_str, d2_str, res_str, res.type, + expected_str, tests[j].expected.type); } sdb_data_free_datum(&res);