Code

Merged branch 'master' of git://git.tokkee.org/sysdb.
authorSebastian Harl <sh@tokkee.org>
Fri, 31 Jan 2014 06:27:24 +0000 (07:27 +0100)
committerSebastian Harl <sh@tokkee.org>
Fri, 31 Jan 2014 06:27:24 +0000 (07:27 +0100)
17 files changed:
configure.ac
src/Makefile.am
src/backend/puppet/store-configs.c
src/client/sock.c
src/core/data.c [new file with mode: 0644]
src/core/store.c
src/include/core/data.h
src/include/core/store.h
src/tools/sysdb/command.c
src/utils/dbi.c
src/utils/unixsock.c
t/Makefile.am
t/core/data_test.c [new file with mode: 0644]
t/core/store_test.c
t/libsysdb_test.c
t/libsysdb_test.h
t/utils/dbi_test.c

index ac281225e0a703cb0478aa4a809f358bcf3360ff..5cae366f0e47b6d16ee649b491ae17d34a8e7d2c 100644 (file)
@@ -254,11 +254,15 @@ AC_ARG_WITH([libdbi],
                [AS_HELP_STRING([--with-libdbi], [libdbi support (default: auto)])],
                [with_libdbi="$withval"],
                [with_libdbi="yes"])
-if test "x$with_libdbi" = "xyes"; then
+if test "x$with_libdbi" = "xyes" || test "x$with_libdbi" = "xauto"; then
        AC_CHECK_HEADERS([dbi/dbi.h],
                        [with_libdbi="yes"],
                        [with_libdbi="no (dbi/dbi.h not found)"])
-fi
+else if test "x$with_libdbi" = "xno"; then
+       with_libdbi="$with_libdbi (disabled on command-line)"
+else
+       AC_MSG_ERROR([Invalid value for option --with-libdbi=$with_libdbi (expected "yes", "no", or "auto")])
+fi; fi
 if test "x$with_libdbi" = "xyes"; then
        AC_CHECK_LIB([dbi], [dbi_initialize],
                        [with_libdbi="yes"],
@@ -287,7 +291,12 @@ AC_ARG_WITH([readline],
 
 if test "x$readline_support" = "xyes"; then
        readline_support="auto"
-fi
+else if test "x$readline_support" != "xauto" \
+               && test "x$readline_support" != "xno" \
+               && test "x$readline_support" != "xlibedit" \
+               && test "x$readline_support" != "xlibreadline"; then
+       AC_MSG_ERROR([Invalid value for option --with-readline=$readline_support (expected "yes", "no", "auto", "libedit", or "libreadline")])
+fi; fi
 
 have_libedit="no"
 if test "x$readline_support" = "xauto" \
@@ -395,10 +404,14 @@ AC_SDB_PLUGIN([mk-livestatus], [yes],
                [backend accessing Nagios/Icinga/Shinken using MK Livestatus])
 AC_SDB_PLUGIN([puppet-storeconfigs], [$puppet_storeconfigs_default],
                [backend accessing the Puppet stored configuration database])
-AC_SDB_PLUGIN([syslog], [yes],
-               [plugin logging to syslog])
+
+m4_divert_once([HELP_ENABLE], [
+Plugins:])
+
 AC_SDB_PLUGIN([cname-dns], [yes],
                [canonicalize hostnames by querying DNS])
+AC_SDB_PLUGIN([syslog], [yes],
+               [plugin logging to syslog])
 
 AM_CONDITIONAL([BUILD_DOCUMENTATION], test "x$build_documentation" = "xyes")
 AM_CONDITIONAL([BUILD_TESTING], test "x$build_testing" = "xyes")
@@ -442,6 +455,7 @@ AC_MSG_RESULT([    puppet-storeconfigs:  . . . $enable_puppet_storeconfigs])
 AC_MSG_RESULT()
 AC_MSG_RESULT([  Plugins:])
 AC_MSG_RESULT([    cname::dns: . . . . . . . . $enable_cname_dns])
+AC_MSG_RESULT([    syslog: . . . . . . . . . . $enable_syslog])
 AC_MSG_RESULT()
 AC_MSG_RESULT([This package is maintained by $PACKAGE_MAINTAINER.])
 AC_MSG_RESULT([Please report bugs to $PACKAGE_BUGREPORT.])
index 9206e27c956fab434980d3658e5438880aa10651..873694874bc06645af68624bb93bbdb23204d875 100644 (file)
@@ -66,7 +66,7 @@ libsysdb_la_SOURCES = \
                core/object.c include/core/object.h \
                core/plugin.c include/core/plugin.h \
                core/store.c include/core/store.h \
-               include/core/data.h \
+               core/data.c include/core/data.h \
                frontend/connection.c include/frontend/connection.h \
                frontend/connection-private.h \
                frontend/parser.c include/frontend/parser.h \
@@ -129,6 +129,14 @@ pkgbackendcollectdlib_LTLIBRARIES =
 pkgbackendpuppetlib_LTLIBRARIES =
 pkgcnamelib_LTLIBRARIES =
 
+if BUILD_PLUGIN_CNAMEDNS
+pkgcnamelib_LTLIBRARIES += plugins/cname/dns.la
+plugins_cname_dns_la_SOURCE = plugins/cname/dns.c
+plugins_cname_dns_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
+libsysdb_la_LIBADD += -dlopen plugins/cname/dns.la
+libsysdb_la_DEPENDENCIES += plugins/cname/dns.la
+endif
+
 if BUILD_PLUGIN_COLLECTD
 pkgbackendcollectdlib_LTLIBRARIES += backend/collectd/unixsock.la
 backend_collectd_unixsock_la_SOURCES = backend/collectd/unixsock.c
@@ -161,14 +169,6 @@ libsysdb_la_LIBADD += -dlopen plugins/syslog.la
 libsysdb_la_DEPENDENCIES += plugins/syslog.la
 endif
 
-if BUILD_PLUGIN_CNAMEDNS
-pkgcnamelib_LTLIBRARIES += plugins/cname/dns.la
-plugins_cname_dns_la_SOURCE = plugins/cname/dns.c
-plugins_cname_dns_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
-libsysdb_la_LIBADD += -dlopen plugins/cname/dns.la
-libsysdb_la_DEPENDENCIES += plugins/cname/dns.la
-endif
-
 include/client/sysdb.h: include/client/sysdb.h.in ../version
        source ../version; sed \
            -e "s/@SDB_VERSION_MAJOR@/$$VERSION_MAJOR/g" \
index a9a0ff777e9d6f35bd364885832b485d1f88beef..e109b305819cfcec5fb1d7f32403241ed519d69b 100644 (file)
@@ -87,7 +87,7 @@ sdb_puppet_stcfg_get_attrs(sdb_dbi_client_t __attribute__((unused)) *client,
 
        const char *hostname;
        const char *key;
-       const char *value;
+       sdb_data_t  value;
        sdb_time_t  last_update;
 
        assert(n == 4);
@@ -98,10 +98,11 @@ sdb_puppet_stcfg_get_attrs(sdb_dbi_client_t __attribute__((unused)) *client,
 
        hostname = data[0].data.string;
        key = data[1].data.string;
-       value = data[2].data.string;
+       value.type = SDB_TYPE_STRING;
+       value.data.string = data[2].data.string;
        last_update = data[3].data.datetime;
 
-       status = sdb_store_attribute(hostname, key, value, last_update);
+       status = sdb_store_attribute(hostname, key, &value, last_update);
 
        if (status < 0) {
                sdb_log(SDB_LOG_ERR, "puppet::store-configs backend: Failed to "
index 49cefdf0935fb8315cda15c6b8921bbfa6d0a510..59c77873e08411b22a9c1e5a6a857a8e269210f5 100644 (file)
@@ -230,14 +230,14 @@ sdb_client_recv(sdb_client_t *client,
 
        size_t data_offset = sdb_strbuf_len(buf);
 
+       if (code)
+               *code = UINT32_MAX;
+
        if ((! client) || (! client->fd) || (! buf)) {
                errno = EBADF;
                return -1;
        }
 
-       if (code)
-               *code = UINT32_MAX;
-
        while (42) {
                ssize_t status;
 
diff --git a/src/core/data.c b/src/core/data.c
new file mode 100644 (file)
index 0000000..1bb5400
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SysDB - src/core/data.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/data.h"
+
+#include <inttypes.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * public API
+ */
+
+int
+sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src)
+{
+       sdb_data_t tmp;
+
+       if ((! dst) || (! src))
+               return -1;
+
+       tmp = *src;
+       switch (src->type) {
+               case SDB_TYPE_STRING:
+                       tmp.data.string = strdup(src->data.string);
+                       if (! tmp.data.string)
+                               return -1;
+                       break;
+               case SDB_TYPE_BINARY:
+                       tmp.data.binary.datum = malloc(src->data.binary.length);
+                       if (! tmp.data.binary.datum)
+                               return -1;
+                       memcpy(tmp.data.binary.datum, src->data.binary.datum,
+                                       src->data.binary.length);
+                       break;
+       }
+
+       *dst = tmp;
+       return 0;
+} /* sdb_data_copy */
+
+void
+sdb_data_free_datum(sdb_data_t *datum)
+{
+       if (! datum)
+               return;
+
+       switch (datum->type) {
+               case SDB_TYPE_STRING:
+                       if (datum->data.string)
+                               free(datum->data.string);
+                       datum->data.string = NULL;
+                       break;
+               case SDB_TYPE_BINARY:
+                       if (datum->data.binary.datum)
+                               free(datum->data.binary.datum);
+                       datum->data.binary.datum = NULL;
+                       datum->data.binary.length = 0;
+                       break;
+       }
+} /* sdb_data_free_datum */
+
+int
+sdb_data_format(sdb_data_t *datum, sdb_strbuf_t *buf)
+{
+       if ((! datum) || (! buf))
+               return -1;
+
+       switch (datum->type) {
+               case SDB_TYPE_INTEGER:
+                       sdb_strbuf_append(buf, "%"PRIi64, datum->data.integer);
+                       break;
+               case SDB_TYPE_DECIMAL:
+                       sdb_strbuf_append(buf, "%a", datum->data.decimal);
+                       break;
+               case SDB_TYPE_STRING:
+                       /* TODO: escape special characters */
+                       sdb_strbuf_append(buf, "\"%s\"", datum->data.string);
+                       break;
+               case SDB_TYPE_DATETIME:
+                       {
+                               char tmp[64];
+                               if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
+                                                       datum->data.datetime))
+                                       return -1;
+                               tmp[sizeof(tmp) - 1] = '\0';
+                               sdb_strbuf_append(buf, "%s", tmp);
+                       }
+                       break;
+               case SDB_TYPE_BINARY:
+                       {
+                               size_t i;
+                               /* TODO: improve this! */
+                               sdb_strbuf_append(buf, "%s", "\"");
+                               for (i = 0; i < datum->data.binary.length; ++i)
+                                       sdb_strbuf_append(buf, "\\%x",
+                                                       (int)datum->data.binary.datum[i]);
+                               sdb_strbuf_append(buf, "%s", "\"");
+                       }
+                       break;
+               default:
+                       return -1;
+       }
+       return 0;
+} /* sdb_data_format */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
index e8d14a079679a12d5a76ef58735b44920065755d..2522233112a8d125024d9853710ff90565f768d4 100644 (file)
@@ -71,7 +71,7 @@ struct sdb_store_base {
 typedef struct {
        sdb_store_base_t super;
 
-       char *value;
+       sdb_data_t value;
 } sdb_attribute_t;
 #define SDB_ATTR(obj) ((sdb_attribute_t *)(obj))
 #define SDB_CONST_ATTR(obj) ((const sdb_attribute_t *)(obj))
@@ -158,20 +158,19 @@ sdb_store_obj_destroy(sdb_object_t *obj)
 static int
 sdb_attr_init(sdb_object_t *obj, va_list ap)
 {
-       const char *value;
+       const sdb_data_t *value;
        int ret;
 
-       /* this will consume the first argument (type) of ap */
+       /* this will consume the first two arguments
+        * (type and last_update) of ap */
        ret = store_base_init(obj, ap);
        if (ret)
                return ret;
-       value = va_arg(ap, const char *);
+       value = va_arg(ap, const sdb_data_t *);
 
-       if (value) {
-               SDB_ATTR(obj)->value = strdup(value);
-               if (! SDB_ATTR(obj)->value)
+       if (value)
+               if (sdb_data_copy(&SDB_ATTR(obj)->value, value))
                        return -1;
-       }
        return 0;
 } /* sdb_attr_init */
 
@@ -181,9 +180,7 @@ sdb_attr_destroy(sdb_object_t *obj)
        assert(obj);
 
        store_base_destroy(obj);
-
-       if (SDB_ATTR(obj)->value)
-               free(SDB_ATTR(obj)->value);
+       sdb_data_free_datum(&SDB_ATTR(obj)->value);
 } /* sdb_attr_destroy */
 
 static sdb_type_t sdb_store_obj_type = {
@@ -416,8 +413,9 @@ store_obj_tojson(sdb_llist_t *list, int type, sdb_strbuf_t *buf)
 
                sdb_strbuf_append(buf, "{\"name\": \"%s\", ", SDB_OBJ(sobj)->name);
                if (type == SDB_ATTRIBUTE)
+                       /* XXX: this needs to be type-dependent */
                        sdb_strbuf_append(buf, "\"value\": \"%s\", ",
-                                       SDB_ATTR(sobj)->value);
+                                       SDB_ATTR(sobj)->value.data.string);
                sdb_strbuf_append(buf, "\"last_update\": \"%s\"}", time_str);
 
                if (sdb_llist_iter_has_next(iter))
@@ -477,7 +475,8 @@ sdb_store_get_host(const char *name)
 } /* sdb_store_get_host */
 
 int
-sdb_store_attribute(const char *hostname, const char *key, const char *value,
+sdb_store_attribute(const char *hostname,
+               const char *key, const sdb_data_t *value,
                sdb_time_t last_update)
 {
        int status;
@@ -494,8 +493,7 @@ sdb_store_attribute(const char *hostname, const char *key, const char *value,
 
        if (status >= 0) {
                assert(updated_attr);
-               SDB_ATTR(updated_attr)->value = strdup(value);
-               if (! SDB_ATTR(updated_attr)->value) {
+               if (sdb_data_copy(&SDB_ATTR(updated_attr)->value, value)) {
                        sdb_object_deref(SDB_OBJ(updated_attr));
                        status = -1;
                }
index 4a4dd2d3385e5f2fbf9e17fbd39cf0e2161772b4..58e92cde59583dd7b114b163304223ecdb2f5d9c 100644 (file)
@@ -29,6 +29,7 @@
 #define SDB_CORE_DATA_H 1
 
 #include "core/time.h"
+#include "utils/strbuf.h"
 
 #include <inttypes.h>
 #include <stddef.h>
@@ -48,25 +49,57 @@ enum {
 /*
  * sdb_data_t:
  * A datum retrieved from an arbitrary data source.
- *
- * The string and binary objects are managed by whoever creates the data
- * object, thus, they must not be freed or modified. If you want to keep them,
- * make sure to make a copy.
  */
 typedef struct {
        int type;
        union {
                int64_t     integer;  /* SDB_TYPE_INTEGER */
                double      decimal;  /* SDB_TYPE_DECIMAL */
-               const char *string;   /* SDB_TYPE_STRING  */
+               char       *string;   /* SDB_TYPE_STRING  */
                sdb_time_t  datetime; /* SDB_TYPE_DATETIME */
                struct {
                        size_t length;
-                       const unsigned char *datum;
+                       unsigned char *datum;
                } binary;             /* SDB_TYPE_BINARY */
        } data;
 } sdb_data_t;
 
+/*
+ * sdb_data_copy:
+ * Copy the datum stored in 'src' to the memory location pointed to by 'dst'.
+ * Any dynamic data (strings, binary data) is copied to newly allocated
+ * memory. Use, for example, sdb_data_free_datum() to free any dynamic memory
+ * stored in a datum.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src);
+
+/*
+ * sdb_data_free_datum:
+ * Free any dynamic memory referenced by the specified datum. Does not free
+ * the memory allocated for the sdb_data_t object itself. This function must
+ * not be used if any static or stack memory is referenced from the data
+ * object.
+ */
+void
+sdb_data_free_datum(sdb_data_t *datum);
+
+/*
+ * sdb_data_format:
+ * Append the specified datum to the specified string buffer using a default
+ * format.
+ *
+ * Returns:
+ *  - 0 on success
+ *  - a negative value else
+ */
+int
+sdb_data_format(sdb_data_t *datum, sdb_strbuf_t *buf);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index ab11a21776a193a460da5e3a8e100b4d1f25cff7..100aadf260700bdbb0c77f59c16cfedd0ca50048 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "sysdb.h"
 #include "core/object.h"
+#include "core/data.h"
 #include "core/time.h"
 #include "utils/llist.h"
 #include "utils/strbuf.h"
@@ -95,7 +96,8 @@ sdb_store_get_host(const char *name);
  *  - a negative value on error
  */
 int
-sdb_store_attribute(const char *hostname, const char *key, const char *value,
+sdb_store_attribute(const char *hostname,
+               const char *key, const sdb_data_t *value,
                sdb_time_t last_update);
 
 /*
index 30e6419e334d1b105749db8861826f2adf5f2883..f948d3aed65a5c18c78565819bdfac522b1cbe37 100644 (file)
 #include "tools/sysdb/input.h"
 
 #include "frontend/proto.h"
+#include "utils/error.h"
 #include "utils/strbuf.h"
 
+#include <errno.h>
+
 #include <assert.h>
 #include <ctype.h>
 #include <string.h>
@@ -66,6 +69,7 @@ sdb_command_exec(sdb_input_t *input)
 
        if (query_len) {
                sdb_strbuf_t *recv_buf;
+               const char *result;
                uint32_t rcode = 0;
 
                recv_buf = sdb_strbuf_create(1024);
@@ -81,7 +85,13 @@ sdb_command_exec(sdb_input_t *input)
 
                if (rcode == UINT32_MAX)
                        printf("ERROR: ");
-               printf("%s\n", sdb_strbuf_string(recv_buf));
+               result = sdb_strbuf_string(recv_buf);
+               if (result && *result)
+                       printf("%s\n", result);
+               else if (rcode == UINT32_MAX) {
+                       char errbuf[1024];
+                       printf("%s\n", sdb_strerror(errno, errbuf, sizeof(errbuf)));
+               }
 
                sdb_strbuf_destroy(recv_buf);
        }
index 1de2f1abe678b74dae092b4b51b40a888b68ceb0..a30f548db2c6661242970d5db6c639b93aa480c8 100644 (file)
@@ -84,7 +84,7 @@ sdb_dbi_get_field(dbi_result res, unsigned int i,
                        data->data.decimal = dbi_result_get_double_idx(res, i);
                        break;
                case SDB_TYPE_STRING:
-                       data->data.string = dbi_result_get_string_idx(res, i);
+                       data->data.string = dbi_result_get_string_copy_idx(res, i);
                        break;
                case SDB_TYPE_DATETIME:
                        {
@@ -96,7 +96,7 @@ sdb_dbi_get_field(dbi_result res, unsigned int i,
                case SDB_TYPE_BINARY:
                        {
                                size_t length = dbi_result_get_field_length_idx(res, i);
-                               const unsigned char *datum = dbi_result_get_binary_idx(res, i);
+                               unsigned char *datum = dbi_result_get_binary_copy_idx(res, i);
                                data->data.binary.length = length;
                                data->data.binary.datum = datum;
                        }
@@ -141,6 +141,8 @@ sdb_dbi_get_data(sdb_dbi_client_t *client, dbi_result res,
                return -1;
 
        for (n = 0; n < num_rows; ++n) {
+               int status;
+
                if (! dbi_result_seek_row(res, n + 1)) {
                        sdb_log(SDB_LOG_ERR, "dbi: Failed to retrieve row %llu: %s",
                                        n, sdb_dbi_strerror(client->conn));
@@ -152,7 +154,11 @@ sdb_dbi_get_data(sdb_dbi_client_t *client, dbi_result res,
                                                types[i], &data[i]))
                                continue;
 
-               if (callback(client, num_fields, data, user_data))
+               status = callback(client, num_fields, data, user_data);
+               for (i = 0; i < num_fields; ++i)
+                       sdb_data_free_datum(&data[i]);
+
+               if (status)
                        continue;
 
                ++success;
index 62b6f45aa404f360ed1f623c07362dcb2c2e26b0..9a5c3fab8c91de6c510a99d8740e4ae2301e0a01 100644 (file)
@@ -113,7 +113,7 @@ sdb_unixsock_parse_cell(char *string, int type, sdb_data_t *data)
                case SDB_TYPE_BINARY:
                        /* we don't support any binary information containing 0-bytes */
                        data->data.binary.length = strlen(string);
-                       data->data.binary.datum = (const unsigned char *)string;
+                       data->data.binary.datum = (unsigned char *)string;
                        break;
                default:
                        sdb_log(SDB_LOG_ERR, "unixsock: Unexpected type %i while "
index 6adf484bf9ab8acca0761c7a93c8a7ea5f35a095..3c13ad556b78c35b04b3907f223106dd0925e69e 100644 (file)
@@ -10,6 +10,7 @@ check_PROGRAMS = libsysdb_test libsysdb_net_test
 
 libsysdb_test_SOURCES = \
                libsysdb_test.c libsysdb_test.h \
+               core/data_test.c \
                core/object_test.c \
                core/store_test.c \
                frontend/parser_test.c \
diff --git a/t/core/data_test.c b/t/core/data_test.c
new file mode 100644 (file)
index 0000000..fb3b114
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * SysDB - t/core/data_test.c
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core/data.h"
+#include "libsysdb_test.h"
+
+#include <check.h>
+
+START_TEST(test_data)
+{
+       sdb_data_t d1, d2;
+       int check;
+
+       d2.type = SDB_TYPE_INTEGER;
+       d2.data.integer = 4711;
+       check = sdb_data_copy(&d1, &d2);
+       fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+       fail_unless(d1.type == d2.type,
+                       "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+                       d1.type, d2.type);
+       fail_unless(d1.data.integer == d2.data.integer,
+                       "sdb_data_copy() didn't copy integer data: got: %d; expected: %d",
+                       d1.data.integer, d2.data.integer);
+
+       d2.type = SDB_TYPE_DECIMAL;
+       d2.data.decimal = 47.11;
+       check = sdb_data_copy(&d1, &d2);
+       fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+       fail_unless(d1.type == d2.type,
+                       "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+                       d1.type, d2.type);
+       fail_unless(d1.data.decimal == d2.data.decimal,
+                       "sdb_data_copy() didn't copy decimal data: got: %f; expected: %f",
+                       d1.data.decimal, d2.data.decimal);
+
+       d2.type = SDB_TYPE_STRING;
+       d2.data.string = "some string";
+       check = sdb_data_copy(&d1, &d2);
+       fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+       fail_unless(d1.type == d2.type,
+                       "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+                       d1.type, d2.type);
+       fail_unless(!strcmp(d1.data.string, d2.data.string),
+                       "sdb_data_copy() didn't copy string data: got: %s; expected: %s",
+                       d1.data.string, d2.data.string);
+
+       sdb_data_free_datum(&d1);
+       fail_unless(d1.data.string == NULL,
+                       "sdb_data_free_datum() didn't free string data");
+
+       d2.type = SDB_TYPE_DATETIME;
+       d2.data.datetime = 4711;
+       check = sdb_data_copy(&d1, &d2);
+       fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+       fail_unless(d1.type == d2.type,
+                       "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+                       d1.type, d2.type);
+       fail_unless(d1.data.datetime == d2.data.datetime,
+                       "sdb_data_copy() didn't copy datetime data: got: %d; expected: %d",
+                       d1.data.datetime, d2.data.datetime);
+
+       d2.type = SDB_TYPE_BINARY;
+       d2.data.binary.datum = (unsigned char *)"some string";
+       d2.data.binary.length = strlen((const char *)d2.data.binary.datum);
+       check = sdb_data_copy(&d1, &d2);
+       fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+       fail_unless(d1.type == d2.type,
+                       "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+                       d1.type, d2.type);
+       fail_unless(d1.data.binary.length == d2.data.binary.length,
+                       "sdb_data_copy() didn't copy length; got: %d; expected: 5d",
+                       d1.data.binary.length, d2.data.binary.length);
+       fail_unless(!memcmp(d1.data.binary.datum, d2.data.binary.datum,
+                               d2.data.binary.length),
+                       "sdb_data_copy() didn't copy binary data: got: %s; expected: %s",
+                       d1.data.string, d2.data.string);
+
+       sdb_data_free_datum(&d1);
+       fail_unless(d1.data.binary.length == 0,
+                       "sdb_data_free_datum() didn't reset binary datum length");
+       fail_unless(d1.data.binary.datum == NULL,
+                       "sdb_data_free_datum() didn't free binary datum");
+}
+END_TEST
+
+START_TEST(test_format)
+{
+       sdb_data_t datum;
+       sdb_strbuf_t *buf;
+       const char *string;
+       const char *expected;
+
+       int check;
+
+       buf = sdb_strbuf_create(1024);
+       fail_unless(buf != NULL,
+                       "INTERNAL ERROR: Failed to allocate string buffer");
+
+       datum.type = SDB_TYPE_INTEGER;
+       datum.data.integer = 4711;
+       check = sdb_data_format(&datum, buf);
+       fail_unless(! check,
+                       "sdb_data_format(INTEGER) = %d; expected: 0", check);
+       string = sdb_strbuf_string(buf);
+       expected = "4711";
+       fail_unless(! strcmp(string, expected),
+                       "sdb_data_format() used wrong format: %s; expected: %s",
+                       string, expected);
+
+       datum.type = SDB_TYPE_DECIMAL;
+       datum.data.decimal = 65536.0;
+       sdb_strbuf_clear(buf);
+       check = sdb_data_format(&datum, buf);
+       fail_unless(! check,
+                       "sdb_data_format(DECIMAL) = %d; expected: 0", check);
+       string = sdb_strbuf_string(buf);
+       expected = "0x1p+16";
+       fail_unless(! strcmp(string, expected),
+                       "sdb_data_format() used wrong format: %s; expected: %s",
+                       string, expected);
+
+       datum.type = SDB_TYPE_STRING;
+       datum.data.string = "this is a test";
+       sdb_strbuf_clear(buf);
+       check = sdb_data_format(&datum, buf);
+       fail_unless(! check,
+                       "sdb_data_format(STRING) = %d; expected: 0", check);
+       string = sdb_strbuf_string(buf);
+       expected = "\"this is a test\"";
+       fail_unless(! strcmp(string, expected),
+                       "sdb_data_format() used wrong format: %s; expected: %s",
+                       string, expected);
+
+       datum.type = SDB_TYPE_DATETIME;
+       datum.data.datetime = 471147114711471100;
+       sdb_strbuf_clear(buf);
+       check = sdb_data_format(&datum, buf);
+       fail_unless(! check,
+                       "sdb_data_format(DATETIME) = %d; expected: 0", check);
+       string = sdb_strbuf_string(buf);
+       expected = "1984-12-06 02:11:54 +0000";
+       fail_unless(! strcmp(string, expected),
+                       "sdb_data_format() used wrong format: %s; expected: %s",
+                       string, expected);
+
+       datum.type = SDB_TYPE_BINARY;
+       datum.data.binary.datum = (unsigned char *)"binary\0crap\x42";
+       datum.data.binary.length = 12;
+       sdb_strbuf_clear(buf);
+       check = sdb_data_format(&datum, buf);
+       fail_unless(! check,
+                       "sdb_data_format(BINARY) = %d; expected: 0", check);
+       string = sdb_strbuf_string(buf);
+       expected = "\"\\62\\69\\6e\\61\\72\\79\\0\\63\\72\\61\\70\\42\"";
+       fail_unless(! strcmp(string, expected),
+                       "sdb_data_format() used wrong format: %s; expected: %s",
+                       string, expected);
+}
+END_TEST
+
+Suite *
+core_data_suite(void)
+{
+       Suite *s = suite_create("core::data");
+       TCase *tc;
+
+       tc = tcase_create("core");
+       tcase_add_test(tc, test_data);
+       tcase_add_test(tc, test_format);
+       suite_add_tcase(s, tc);
+
+       return s;
+} /* core_data_suite */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+
index effd05a7d5d8425f89b5f8db7d9f6d818b490940..855c8c09e857b4b821e022bda2ec5f23d525856f 100644 (file)
@@ -147,7 +147,7 @@ START_TEST(test_store_attr)
        struct {
                const char *host;
                const char *key;
-               const char *value;
+               char       *value;
                sdb_time_t  last_update;
                int         expected;
        } golden_data[] = {
@@ -166,10 +166,15 @@ START_TEST(test_store_attr)
        sdb_store_host("l", 1);
        sdb_store_host("m", 1);
        for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) {
+               sdb_data_t datum;
                int status;
 
+               /* XXX: test other types as well */
+               datum.type = SDB_TYPE_STRING;
+               datum.data.string = golden_data[i].value;
+
                status = sdb_store_attribute(golden_data[i].host,
-                               golden_data[i].key, golden_data[i].value,
+                               golden_data[i].key, &datum,
                                golden_data[i].last_update);
                fail_unless(status == golden_data[i].expected,
                                "sdb_store_attribute(%s, %s, %s, %d) = %d; expected: %d",
@@ -244,6 +249,7 @@ verify_json_output(sdb_strbuf_t *buf, const char *expected, int flags)
 START_TEST(test_store_tojson)
 {
        sdb_strbuf_t *buf;
+       sdb_data_t datum;
        size_t i;
 
        struct {
@@ -296,9 +302,13 @@ START_TEST(test_store_tojson)
        sdb_store_host("h1", 1);
        sdb_store_host("h2", 1);
 
-       sdb_store_attribute("h1", "k1", "v1", 1);
-       sdb_store_attribute("h1", "k2", "v2", 1);
-       sdb_store_attribute("h1", "k3", "v3", 1);
+       datum.type = SDB_TYPE_STRING;
+       datum.data.string = "v1";
+       sdb_store_attribute("h1", "k1", &datum, 1);
+       datum.data.string = "v2";
+       sdb_store_attribute("h1", "k2", &datum, 1);
+       datum.data.string = "v3";
+       sdb_store_attribute("h1", "k3", &datum, 1);
 
        sdb_store_service("h2", "s1", 1);
        sdb_store_service("h2", "s2", 1);
index 2fa83dc6af7f4dcbd758e19459cc8b37e37a7cde..c7787e4466bfc5fee7ec4e9869e7f42ddefe934e 100644 (file)
@@ -38,6 +38,7 @@ main(void)
        size_t i;
 
        suite_creator_t creators[] = {
+               { core_data_suite, NULL },
                { core_object_suite, NULL },
                { core_store_suite, NULL },
                { fe_parser_suite, NULL },
index 64558cdadebfb2861f3c6f0fb459d7307c28eb65..5539d63290e54a258350c05a6846819820ae27d7 100644 (file)
@@ -59,6 +59,10 @@ typedef struct {
  * test suites
  */
 
+/* t/core/data_test */
+Suite *
+core_data_suite(void);
+
 /* t/core/object_test */
 Suite *
 core_object_suite(void);
index 10447e9962980108c1aa430ad27253f0d2d381f2..c54ea3164dec8b965bb16a4d64368bbac6b3b694 100644 (file)
@@ -331,6 +331,17 @@ dbi_result_get_string_idx(dbi_result res, unsigned int i)
        return get_golden_data(res, i).string;
 } /* dbi_result_get_string_idx */
 
+char *
+dbi_result_get_string_copy_idx(dbi_result res, unsigned int i)
+{
+       fail_unless(current_query->field_types[i - 1] == DBI_TYPE_STRING,
+                       "dbi_result_get_string_copy_idx() called for non-string "
+                       "column type %u", current_query->field_types[i - 1]);
+       if (! get_golden_data(res, i).string)
+               return NULL;
+       return strdup(get_golden_data(res, i).string);
+} /* dbi_result_get_string_copy_idx */
+
 time_t
 dbi_result_get_datetime_idx(dbi_result res, unsigned int i)
 {
@@ -379,6 +390,19 @@ dbi_result_get_binary_idx(dbi_result res, unsigned int i)
        return get_golden_data(res, i).binary.datum;
 } /* dbi_result_get_binary_idx */
 
+unsigned char *
+dbi_result_get_binary_copy_idx(dbi_result res, unsigned int i)
+{
+       const char *data;
+       fail_unless(current_query->field_types[i - 1] == DBI_TYPE_BINARY,
+                       "dbi_result_get_binary_copy_idx() called for non-binary "
+                       "column type %u", current_query->field_types[i - 1]);
+       data = (const char *)get_golden_data(res, i).binary.datum;
+       if (! data)
+               return NULL;
+       return (unsigned char *)strdup(data);
+} /* dbi_result_get_binary_copy_idx */
+
 static unsigned long long dbi_result_free_called = 0;
 int
 dbi_result_free(dbi_result res)
@@ -467,7 +491,7 @@ query_callback(sdb_dbi_client_t *c,
                                                data[i].data.decimal, i, expected_data.decimal);
                                break;
                        case SDB_TYPE_STRING:
-                               fail_unless(data[i].data.string == expected_data.string,
+                               fail_unless(!strcmp(data[i].data.string, expected_data.string),
                                                "query callback received unexpected data %s "
                                                "for column %zu; expected: %s",
                                                data[i].data.string, i, expected_data.string);
@@ -487,8 +511,9 @@ query_callback(sdb_dbi_client_t *c,
                                                "binary data length %zu for column %zu; "
                                                "expected: %lli", data[i].data.binary.length, i,
                                                expected_data.binary.length);
-                               fail_unless(data[i].data.binary.datum ==
+                               fail_unless(!memcmp(data[i].data.binary.datum,
                                                        expected_data.binary.datum,
+                                                       expected_data.binary.length),
                                                "query callback received unexpected binary data %p "
                                                "for column %zu; expected: %p",
                                                data[i].data.binary.datum, i,