summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 32cb89d)
raw | patch | inline | side by side (parent: 32cb89d)
author | Sebastian Harl <sh@tokkee.org> | |
Sun, 19 Oct 2014 12:56:38 +0000 (14:56 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Sun, 19 Oct 2014 12:56:38 +0000 (14:56 +0200) |
… and let all expressions involving NULL values to return NULL.
src/core/data.c | patch | blob | history | |
src/include/core/data.h | patch | blob | history | |
t/unit/core/data_test.c | patch | blob | history |
diff --git a/src/core/data.c b/src/core/data.c
index 4840736896f55a03b4cf0716e18e3dec7cb9baec..f489367a42218e35a94bbf64afbff7d6255442fb 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
#include "core/data.h"
#include "utils/error.h"
+#include <assert.h>
+
#include <errno.h>
#include <inttypes.h>
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) {
* 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)
{
{
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))
{
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);
index ffddf979f5509593417c80d6b3358b0b75e27a34..514c4d524ce2dd04dc463ff6b7e51254dede129f 100644 (file)
--- a/src/include/core/data.h
+++ b/src/include/core/data.h
#endif
enum {
- SDB_TYPE_INTEGER = 1,
+ SDB_TYPE_NULL = 0,
+ SDB_TYPE_INTEGER,
SDB_TYPE_DECIMAL,
SDB_TYPE_STRING,
SDB_TYPE_DATETIME,
} 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:
/*
* 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);
* 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:
* - <integer> or <decimal> <mul> <datetime>
index 2336c5e98d335714f510797c31f745126bb938ee..9c736d399e291d12eb61c80ae0c3a83772393d2e 100644 (file)
--- a/t/unit/core/data_test.c
+++ b/t/unit/core/data_test.c
START_TEST(test_expr_eval)
{
+ sdb_data_t err = { -1, { .integer = 0 } };
+
struct {
sdb_data_t d1;
sdb_data_t d2;
{ 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 } },
{ 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" } },
},
{
{ 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,
},
{
{
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" } },
{
{ 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,
},
};
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] = "";
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);