Merge branch 'collectd-5.5'
[collectd.git] / src / utils_db_query.c
index fcded6b..e734358 100644 (file)
@@ -25,6 +25,7 @@
  **/
 
 #include "collectd.h"
+
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
@@ -54,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;
@@ -70,6 +72,7 @@ struct udb_result_preparation_area_s /* {{{ */
   char  **instances_buffer;
   char  **values_buffer;
   char  **metadata_buffer;
+  char   *plugin_instance;
 
   struct udb_result_preparation_area_s *next;
 }; /* }}} */
@@ -78,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;
@@ -122,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)
   {
@@ -131,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)
     {
@@ -142,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)
   {
@@ -151,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)
@@ -196,23 +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;
-  int status;
 
   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];
 
@@ -221,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);
     }
   }
@@ -230,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;
@@ -286,9 +295,9 @@ static int udb_result_submit (udb_result_t *r, /* {{{ */
       return (-ENOMEM);
     }
 
-    for (i = 0; i < r->metadata_num; i++)
+    for (size_t i = 0; i < r->metadata_num; i++)
     {
-      status = meta_data_add_string (vl.meta, r->metadata[i],
+      int status = meta_data_add_string (vl.meta, r->metadata[i],
           r_area->metadata_buffer[i]);
       if (status != 0)
       {
@@ -332,19 +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 (i = 0; i < r->metadata_num; 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 */
 
@@ -352,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);
 
@@ -383,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);
@@ -402,7 +410,7 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
       = (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);
     }
 
@@ -410,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) */
@@ -419,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);
   }
 
@@ -427,7 +435,7 @@ 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);
   }
 
@@ -435,7 +443,7 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     = (size_t *) calloc (r->metadata_num, sizeof (size_t));
   if (prep_area->metadata_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);
   }
 
@@ -443,14 +451,14 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
     = (char **) calloc (r->metadata_num, sizeof (char *));
   if (prep_area->metadata_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);
   }
 
   /* }}} */
 
-  /* 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;
 
@@ -472,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;
 
@@ -496,7 +505,7 @@ 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 (i = 0; i < r->metadata_num; i++)
+  for (size_t i = 0; i < r->metadata_num; i++)
   {
     size_t j;
 
@@ -524,22 +533,21 @@ static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
 
 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 (i = 0; i < r->metadata_num; i++)
+  for (size_t i = 0; i < r->metadata_num; i++)
     sfree (r->metadata[i]);
   sfree (r->metadata);
 
@@ -553,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)
   {
@@ -562,13 +569,12 @@ 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;
@@ -578,7 +584,7 @@ static int udb_result_create (const char *query_name, /* {{{ */
 
   /* 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;
 
@@ -657,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);
 
@@ -675,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);
@@ -690,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)
@@ -708,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;
 
@@ -720,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)
@@ -764,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)
     {
@@ -793,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);
@@ -808,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)
@@ -820,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;
@@ -829,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)
     {
@@ -981,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;",
@@ -1044,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;",
@@ -1055,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)
   {
@@ -1084,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;
@@ -1110,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;
   }