Merge branch 'collectd-5.5'
[collectd.git] / src / utils_db_query.c
index 9a16873..e734358 100644 (file)
@@ -2,24 +2,30 @@
  * collectd - src/utils_db_query.c
  * Copyright (C) 2008,2009  Florian octo Forster
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; only version 2 of the License is applicable.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
  *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  **/
 
 #include "collectd.h"
+
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
@@ -38,6 +44,8 @@ struct udb_result_s
   size_t   instances_num;
   char   **values;
   size_t   values_num;
+  char   **metadata;
+  size_t   metadata_num;
 
   udb_result_t *next;
 }; /* }}} */
@@ -47,6 +55,7 @@ struct udb_query_s /* {{{ */
   char *name;
   char *statement;
   void *user_data;
+  char *plugin_instance_from;
 
   unsigned int min_version;
   unsigned int max_version;
@@ -59,8 +68,11 @@ struct udb_result_preparation_area_s /* {{{ */
   const   data_set_t *ds;
   size_t *instances_pos;
   size_t *values_pos;
+  size_t *metadata_pos;
   char  **instances_buffer;
   char  **values_buffer;
+  char  **metadata_buffer;
+  char   *plugin_instance;
 
   struct udb_result_preparation_area_s *next;
 }; /* }}} */
@@ -69,6 +81,7 @@ typedef struct udb_result_preparation_area_s udb_result_preparation_area_t;
 struct udb_query_preparation_area_s /* {{{ */
 {
   size_t column_num;
+  size_t plugin_instance_pos;
   char *host;
   char *plugin;
   char *db_name;
@@ -113,7 +126,6 @@ static int udb_config_add_string (char ***ret_array, /* {{{ */
 {
   char **array;
   size_t array_len;
-  int i;
 
   if (ci->values_num < 1)
   {
@@ -122,7 +134,7 @@ static int udb_config_add_string (char ***ret_array, /* {{{ */
     return (-1);
   }
 
-  for (i = 0; i < ci->values_num; i++)
+  for (int i = 0; i < ci->values_num; i++)
   {
     if (ci->values[i].type != OCONFIG_TYPE_STRING)
     {
@@ -133,7 +145,7 @@ static int udb_config_add_string (char ***ret_array, /* {{{ */
   }
 
   array_len = *ret_array_len;
-  array = (char **) realloc (*ret_array,
+  array = realloc (*ret_array,
       sizeof (char *) * (array_len + ci->values_num));
   if (array == NULL)
   {
@@ -142,7 +154,7 @@ static int udb_config_add_string (char ***ret_array, /* {{{ */
   }
   *ret_array = array;
 
-  for (i = 0; i < ci->values_num; i++)
+  for (int i = 0; i < ci->values_num; i++)
   {
     array[array_len] = strdup (ci->values[i].value.string);
     if (array[array_len] == NULL)
@@ -187,22 +199,21 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
     udb_query_t const *q, udb_query_preparation_area_t *q_area)
 {
   value_list_t vl = VALUE_LIST_INIT;
-  size_t i;
 
   assert (r != NULL);
   assert (r_area->ds != NULL);
   assert (((size_t) r_area->ds->ds_num) == r->values_num);
   assert (r->values_num > 0);
 
-  vl.values = (value_t *) calloc (r->values_num, sizeof (value_t));
+  vl.values = calloc (r->values_num, sizeof (*vl.values));
   if (vl.values == NULL)
   {
-    ERROR ("db query utils: malloc failed.");
+    ERROR ("db query utils: calloc failed.");
     return (-1);
   }
   vl.values_len = r_area->ds->ds_num;
 
-  for (i = 0; i < r->values_num; i++)
+  for (size_t i = 0; i < r->values_num; i++)
   {
     char *value_str = r_area->values_buffer[i];
 
@@ -211,6 +222,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
       ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
           value_str, DS_TYPE_TO_STRING (r_area->ds->ds[i].type));
       errno = EINVAL;
+      free (vl.values);
       return (-1);
     }
   }
@@ -220,11 +232,18 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
 
   sstrncpy (vl.host, q_area->host, sizeof (vl.host));
   sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
-  sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
   sstrncpy (vl.type, r->type, sizeof (vl.type));
 
+  /* Set vl.plugin_instance */
+  if (q->plugin_instance_from != NULL) {
+    sstrncpy (vl.plugin_instance, r_area->plugin_instance, sizeof (vl.plugin_instance));
+  }
+  else {
+    sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
+  }
+
   /* Set vl.type_instance {{{ */
-  if (r->instances_num <= 0)
+  if (r->instances_num == 0)
   {
     if (r->instance_prefix == NULL)
       vl.type_instance[0] = 0;
@@ -238,7 +257,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
     {
       int status = strjoin (vl.type_instance, sizeof (vl.type_instance),
           r_area->instances_buffer, r->instances_num, "-");
-      if (status != 0)
+      if (status < 0)
       {
         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
             status);
@@ -251,7 +270,7 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
 
       int status = strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
           r->instances_num, "-");
-      if (status != 0)
+      if (status < 0)
       {
         ERROR ("udb_result_submit: creating type_instance failed with status %d.",
             status);
@@ -266,8 +285,38 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
   vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
   /* }}} */
 
+  /* Annotate meta data. {{{ */
+  if (r->metadata_num > 0)
+  {
+    vl.meta = meta_data_create ();
+    if (vl.meta == NULL)
+    {
+      ERROR ("db query utils:: meta_data_create failed.");
+      return (-ENOMEM);
+    }
+
+    for (size_t i = 0; i < r->metadata_num; i++)
+    {
+      int status = meta_data_add_string (vl.meta, r->metadata[i],
+          r_area->metadata_buffer[i]);
+      if (status != 0)
+      {
+        ERROR ("db query utils:: meta_data_add_string failed.");
+        meta_data_destroy (vl.meta);
+        vl.meta = NULL;
+        return (status);
+      }
+    }
+  }
+  /* }}} */
+
   plugin_dispatch_values (&vl);
 
+  if (r->metadata_num > 0)
+  {
+    meta_data_destroy (vl.meta);
+    vl.meta = NULL;
+  }
   sfree (vl.values);
   return (0);
 } /* }}} void udb_result_submit */
@@ -281,8 +330,10 @@ static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
   prep_area->ds = NULL;
   sfree (prep_area->instances_pos);
   sfree (prep_area->values_pos);
+  sfree (prep_area->metadata_pos);
   sfree (prep_area->instances_buffer);
   sfree (prep_area->values_buffer);
+  sfree (prep_area->metadata_buffer);
 } /* }}} void udb_result_finish_result */
 
 static int udb_result_handle_result (udb_result_t *r, /* {{{ */
@@ -290,16 +341,20 @@ static int udb_result_handle_result (udb_result_t *r, /* {{{ */
     udb_result_preparation_area_t *r_area,
     udb_query_t const *q, char **column_values)
 {
-  size_t i;
-
   assert (r && q_area && r_area);
 
-  for (i = 0; i < r->instances_num; i++)
+  for (size_t i = 0; i < r->instances_num; i++)
     r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
 
-  for (i = 0; i < r->values_num; i++)
+  for (size_t i = 0; i < r->values_num; i++)
     r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
 
+  for (size_t i = 0; i < r->metadata_num; i++)
+    r_area->metadata_buffer[i] = column_values[r_area->metadata_pos[i]];
+
+  if (q->plugin_instance_from)
+    r_area->plugin_instance = column_values[q_area->plugin_instance_pos];
+
   return udb_result_submit (r, r_area, q, q_area);
 } /* }}} int udb_result_handle_result */
 
@@ -307,8 +362,6 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     udb_result_preparation_area_t *prep_area,
     char **column_names, size_t column_num)
 {
-  size_t i;
-
   if ((r == NULL) || (prep_area == NULL))
     return (-EINVAL);
 
@@ -316,14 +369,17 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
   prep_area->ds = NULL; \
   sfree (prep_area->instances_pos); \
   sfree (prep_area->values_pos); \
+  sfree (prep_area->metadata_pos); \
   sfree (prep_area->instances_buffer); \
   sfree (prep_area->values_buffer); \
+  sfree (prep_area->metadata_buffer); \
   return (status)
 
   /* Make sure previous preparations are cleaned up. */
   udb_result_finish_result (r, prep_area);
   prep_area->instances_pos = NULL;
   prep_area->values_pos = NULL;
+  prep_area->metadata_pos = NULL;
 
   /* Read `ds' and check number of values {{{ */
   prep_area->ds = plugin_get_ds (r->type);
@@ -335,10 +391,10 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     BAIL_OUT (-1);
   }
 
-  if (((size_t) prep_area->ds->ds_num) != r->values_num)
+  if (prep_area->ds->ds_num != r->values_num)
   {
     ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
-        "requires exactly %i value%s, but the configuration specifies %zu.",
+        "requires exactly %zu value%s, but the configuration specifies %zu.",
         r->type,
         prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
         r->values_num);
@@ -346,15 +402,15 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
   }
   /* }}} */
 
-  /* Allocate r->instances_pos, r->values_pos, r->instances_buffer, and
-   * r->values_buffer {{{ */
+  /* Allocate r->instances_pos, r->values_pos, r->metadata_post,
+   * r->instances_buffer, r->values_buffer, and r->metadata_buffer {{{ */
   if (r->instances_num > 0)
   {
     prep_area->instances_pos
       = (size_t *) calloc (r->instances_num, sizeof (size_t));
     if (prep_area->instances_pos == NULL)
     {
-      ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+      ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
       BAIL_OUT (-ENOMEM);
     }
 
@@ -362,7 +418,7 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
       = (char **) calloc (r->instances_num, sizeof (char *));
     if (prep_area->instances_buffer == NULL)
     {
-      ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+      ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
       BAIL_OUT (-ENOMEM);
     }
   } /* if (r->instances_num > 0) */
@@ -371,7 +427,7 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     = (size_t *) calloc (r->values_num, sizeof (size_t));
   if (prep_area->values_pos == NULL)
   {
-    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
     BAIL_OUT (-ENOMEM);
   }
 
@@ -379,13 +435,30 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     = (char **) calloc (r->values_num, sizeof (char *));
   if (prep_area->values_buffer == NULL)
   {
-    ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
+    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
+    BAIL_OUT (-ENOMEM);
+  }
+
+  prep_area->metadata_pos
+    = (size_t *) calloc (r->metadata_num, sizeof (size_t));
+  if (prep_area->metadata_pos == NULL)
+  {
+    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
     BAIL_OUT (-ENOMEM);
   }
+
+  prep_area->metadata_buffer
+    = (char **) calloc (r->metadata_num, sizeof (char *));
+  if (prep_area->metadata_buffer == NULL)
+  {
+    ERROR ("db query utils: udb_result_prepare_result: calloc failed.");
+    BAIL_OUT (-ENOMEM);
+  }
+
   /* }}} */
 
-  /* Determine the position of the instance columns {{{ */
-  for (i = 0; i < r->instances_num; i++)
+  /* Determine the position of the plugin instance column {{{ */
+  for (size_t i = 0; i < r->instances_num; i++)
   {
     size_t j;
 
@@ -407,8 +480,9 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     }
   } /* }}} for (i = 0; i < r->instances_num; i++) */
 
+
   /* Determine the position of the value columns {{{ */
-  for (i = 0; i < r->values_num; i++)
+  for (size_t i = 0; i < r->values_num; i++)
   {
     size_t j;
 
@@ -430,27 +504,53 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     }
   } /* }}} for (i = 0; i < r->values_num; i++) */
 
+  /* Determine the position of the metadata columns {{{ */
+  for (size_t i = 0; i < r->metadata_num; i++)
+  {
+    size_t j;
+
+    for (j = 0; j < column_num; j++)
+    {
+      if (strcasecmp (r->metadata[i], column_names[j]) == 0)
+      {
+        prep_area->metadata_pos[i] = j;
+        break;
+      }
+    }
+
+    if (j >= column_num)
+    {
+      ERROR ("db query utils: udb_result_prepare_result: "
+          "Metadata column `%s' could not be found.",
+          r->values[i]);
+      BAIL_OUT (-ENOENT);
+    }
+  } /* }}} for (i = 0; i < r->metadata_num; i++) */
+
 #undef BAIL_OUT
   return (0);
 } /* }}} int udb_result_prepare_result */
 
 static void udb_result_free (udb_result_t *r) /* {{{ */
 {
-  size_t i;
-
   if (r == NULL)
     return;
 
   sfree (r->type);
+  sfree (r->instance_prefix);
 
-  for (i = 0; i < r->instances_num; i++)
+  for (size_t i = 0; i < r->instances_num; i++)
     sfree (r->instances[i]);
   sfree (r->instances);
 
-  for (i = 0; i < r->values_num; i++)
+  for (size_t i = 0; i < r->values_num; i++)
     sfree (r->values[i]);
   sfree (r->values);
 
+  for (size_t i = 0; i < r->metadata_num; i++)
+    sfree (r->metadata[i]);
+  sfree (r->metadata);
+
   udb_result_free (r->next);
 
   sfree (r);
@@ -461,7 +561,6 @@ static int udb_result_create (const char *query_name, /* {{{ */
 {
   udb_result_t *r;
   int status;
-  int i;
 
   if (ci->values_num != 0)
   {
@@ -470,22 +569,22 @@ static int udb_result_create (const char *query_name, /* {{{ */
         ci->values_num, (ci->values_num == 1) ? "" : "s");
   }
 
-  r = (udb_result_t *) malloc (sizeof (*r));
+  r = calloc (1, sizeof (*r));
   if (r == NULL)
   {
-    ERROR ("db query utils: malloc failed.");
+    ERROR ("db query utils: calloc failed.");
     return (-1);
   }
-  memset (r, 0, sizeof (*r));
   r->type = NULL;
   r->instance_prefix = NULL;
   r->instances = NULL;
   r->values = NULL;
+  r->metadata = NULL;
   r->next = NULL;
 
   /* Fill the `udb_result_t' structure.. */
   status = 0;
-  for (i = 0; i < ci->children_num; i++)
+  for (int i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *child = ci->children + i;
 
@@ -497,6 +596,8 @@ static int udb_result_create (const char *query_name, /* {{{ */
       status = udb_config_add_string (&r->instances, &r->instances_num, child);
     else if (strcasecmp ("ValuesFrom", child->key) == 0)
       status = udb_config_add_string (&r->values, &r->values_num, child);
+    else if (strcasecmp ("MetadataFrom", child->key) == 0)
+      status = udb_config_add_string (&r->metadata, &r->metadata_num, child);
     else
     {
       WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
@@ -562,6 +663,7 @@ static void udb_query_free_one (udb_query_t *q) /* {{{ */
 
   sfree (q->name);
   sfree (q->statement);
+  sfree (q->plugin_instance_from);
 
   udb_result_free (q->results);
 
@@ -580,7 +682,6 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
 
   udb_query_t *q;
   int status;
-  int i;
 
   if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
     return (-EINVAL);
@@ -595,15 +696,17 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
     return (-1);
   }
 
-  q = (udb_query_t *) malloc (sizeof (*q));
+  q = calloc (1, sizeof (*q));
   if (q == NULL)
   {
-    ERROR ("db query utils: malloc failed.");
+    ERROR ("db query utils: calloc failed.");
     return (-1);
   }
-  memset (q, 0, sizeof (*q));
   q->min_version = 0;
   q->max_version = UINT_MAX;
+  q->statement = NULL;
+  q->results = NULL;
+  q->plugin_instance_from = NULL;
 
   status = udb_config_set_string (&q->name, ci);
   if (status != 0)
@@ -613,7 +716,7 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
   }
 
   /* Fill the `udb_query_t' structure.. */
-  for (i = 0; i < ci->children_num; i++)
+  for (int i = 0; i < ci->children_num; i++)
   {
     oconfig_item_t *child = ci->children + i;
 
@@ -625,6 +728,8 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
       status = udb_config_set_uint (&q->min_version, child);
     else if (strcasecmp ("MaxVersion", child->key) == 0)
       status = udb_config_set_uint (&q->max_version, child);
+    else if (strcasecmp ("PluginInstanceFrom", child->key) == 0)
+      status = udb_config_set_string (&q->plugin_instance_from, child);
 
     /* Call custom callbacks */
     else if (cb != NULL)
@@ -669,7 +774,7 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
   {
     udb_query_t **temp;
 
-    temp = (udb_query_t **) realloc (query_list,
+    temp = realloc (query_list,
         sizeof (*query_list) * (query_list_len + 1));
     if (temp == NULL)
     {
@@ -698,12 +803,10 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
 
 void udb_query_free (udb_query_t **query_list, size_t query_list_len) /* {{{ */
 {
-  size_t i;
-
   if (query_list == NULL)
     return;
 
-  for (i = 0; i < query_list_len; i++)
+  for (size_t i = 0; i < query_list_len; i++)
     udb_query_free_one (query_list[i]);
 
   sfree (query_list);
@@ -713,7 +816,6 @@ int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
     udb_query_t **src_list, size_t src_list_len,
     udb_query_t ***dst_list, size_t *dst_list_len)
 {
-  size_t i;
   int num_added;
 
   if ((name == NULL) || (src_list == NULL) || (dst_list == NULL)
@@ -725,7 +827,7 @@ int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
   }
 
   num_added = 0;
-  for (i = 0; i < src_list_len; i++)
+  for (size_t i = 0; i < src_list_len; i++)
   {
     udb_query_t **tmp_list;
     size_t tmp_list_len;
@@ -734,7 +836,7 @@ int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
       continue;
 
     tmp_list_len = *dst_list_len;
-    tmp_list = (udb_query_t **) realloc (*dst_list, (tmp_list_len + 1)
+    tmp_list = realloc (*dst_list, (tmp_list_len + 1)
         * sizeof (udb_query_t *));
     if (tmp_list == NULL)
     {
@@ -886,9 +988,7 @@ int udb_query_handle_result (udb_query_t const *q, /* {{{ */
 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
   do
   {
-    size_t i;
-
-    for (i = 0; i < prep_area->column_num; i++)
+    for (size_t i = 0; i < prep_area->column_num; i++)
     {
       DEBUG ("db query utils: udb_query_handle_result (%s, %s): "
           "column[%zu] = %s;",
@@ -949,9 +1049,7 @@ int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
   do
   {
-    size_t i;
-
-    for (i = 0; i < column_num; i++)
+    for (size_t i = 0; i < column_num; i++)
     {
       DEBUG ("db query utils: udb_query_prepare_result: "
           "query = %s; column[%zu] = %s;",
@@ -960,6 +1058,31 @@ int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
   } while (0);
 #endif
 
+  /* Determine the position of the PluginInstance column {{{ */
+  if (q->plugin_instance_from != NULL)
+  {
+    size_t i;
+
+    for (i = 0; i < column_num; i++)
+    {
+      if (strcasecmp (q->plugin_instance_from, column_names[i]) == 0)
+      {
+        prep_area->plugin_instance_pos = i;
+        break;
+      }
+    }
+
+    if (i >= column_num)
+    {
+      ERROR ("db query utils: udb_query_prepare_result: "
+          "Column `%s' from `PluginInstanceFrom' could not be found.",
+          q->plugin_instance_from);
+      udb_query_finish_result (q, prep_area);
+      return (-ENOENT);
+    }
+  }
+  /* }}} */
+
   for (r = q->results, r_area = prep_area->result_prep_areas;
       r != NULL; r = r->next, r_area = r_area->next)
   {
@@ -989,17 +1112,16 @@ udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */
   udb_result_preparation_area_t **next_r_area;
   udb_result_t *r;
 
-  q_area = malloc (sizeof (*q_area));
+  q_area = calloc (1, sizeof (*q_area));
   if (q_area == NULL)
     return NULL;
-  memset (q_area, 0, sizeof (*q_area));
 
   next_r_area = &q_area->result_prep_areas;
   for (r = q->results; r != NULL; r = r->next)
   {
     udb_result_preparation_area_t *r_area;
 
-    r_area = malloc (sizeof (*r_area));
+    r_area = calloc (1, sizeof (*r_area));
     if (r_area == NULL)
     {
       udb_result_preparation_area_t *a = q_area->result_prep_areas;
@@ -1015,8 +1137,6 @@ udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */
       return NULL;
     }
 
-    memset (r_area, 0, sizeof (*r_area));
-
     *next_r_area = r_area;
     next_r_area  = &r_area->next;
   }