From: Florian Forster Date: Sat, 14 Feb 2009 14:44:07 +0000 (+0100) Subject: src/utils_db_query.c: Add support for the `Column' configuration option. X-Git-Tag: collectd-4.6.0~36 X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=0bd2ee0aaa95cef6155ba0418ddcc1f68bfa7521;p=collectd.git src/utils_db_query.c: Add support for the `Column' configuration option. The support has been implemented as unobtrusively as possible: - The `udb_result_t' type now has two new members: `legacy_mode' and `legacy_position'. The `legacy_mode' member is used to switch to a new set of functions for handling these special results. - Those ``legacy results'' use only a small subset of the members in `udb_result_t'. The different behavior has been put in the following functions: udb_legacy_result_finish_result udb_legacy_result_handle_result udb_legacy_result_prepare_result udb_legacy_result_create - The non-legacy counterparts to finish, handle, and prepare automatically call the legacy version if the `legacy_mode' member is set to `1'. WARNING: Untested code, the PostgreSQL plugin still needs to be ported. --- diff --git a/src/utils_db_query.c b/src/utils_db_query.c index e50bc584..e1ed7e6d 100644 --- a/src/utils_db_query.c +++ b/src/utils_db_query.c @@ -46,6 +46,15 @@ struct udb_result_s char **instances_buffer; char **values_buffer; + /* Legacy data */ + int legacy_mode; + size_t legacy_position; + /* When in legacy mode: + * - type/ds hold the format of the data + * - instance_prefix is used as type-instance if non-NULL + * - legacy_position holds the index of the column to use as value. + */ + udb_result_t *next; }; /* }}} */ @@ -171,6 +180,175 @@ static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */ } /* }}} int udb_config_set_uint */ /* + * Legacy result private functions + */ +static void udb_legacy_result_finish_result (udb_result_t *r) /* {{{ */ +{ + if (r == NULL) + return; + + assert (r->legacy_mode == 1); + + r->ds = NULL; +} /* }}} void udb_legacy_result_finish_result */ + +static int udb_legacy_result_handle_result (udb_result_t *r, /* {{{ */ + udb_query_t *q, char **column_values) +{ + value_list_t vl = VALUE_LIST_INIT; + value_t value; + char *endptr; + + assert (r->legacy_mode == 1); + assert (r->ds != NULL); + assert (r->ds->ds_num == 1); + + vl.values = &value; + vl.values_len = 1; + + endptr = NULL; + errno = 0; + if (r->ds->ds[0].type == DS_TYPE_COUNTER) + vl.values[0].counter = (counter_t) strtoll (column_values[r->legacy_position], + &endptr, /* base = */ 0); + else if (r->ds->ds[0].type == DS_TYPE_GAUGE) + vl.values[0].gauge = (gauge_t) strtod (column_values[r->legacy_position], + &endptr); + else + errno = EINVAL; + + if ((endptr == column_values[r->legacy_position]) || (errno != 0)) + { + WARNING ("db query utils: udb_result_submit: Parsing `%s' as %s failed.", + column_values[r->legacy_position], + (r->ds->ds[0].type == DS_TYPE_COUNTER) ? "counter" : "gauge"); + vl.values[0].gauge = NAN; + } + + sstrncpy (vl.host, q->host, sizeof (vl.host)); + sstrncpy (vl.plugin, q->plugin, sizeof (vl.plugin)); + sstrncpy (vl.plugin_instance, q->db_name, sizeof (vl.type_instance)); + sstrncpy (vl.type, r->type, sizeof (vl.type)); + + if (r->instance_prefix != NULL) + sstrncpy (vl.type_instance, r->instance_prefix, + sizeof (vl.type_instance)); + + plugin_dispatch_values (&vl); + + return (0); +} /* }}} int udb_legacy_result_handle_result */ + +static int udb_legacy_result_prepare_result (udb_result_t *r, /* {{{ */ + char **column_names, size_t column_num) +{ + if (r == NULL) + return (-EINVAL); + + assert (r->legacy_mode == 1); + + /* Make sure previous preparations are cleaned up. */ + udb_legacy_result_finish_result (r); + + if (r->legacy_position >= column_num) + { + ERROR ("db query utils: The legacy configuration specified (at least) " + "%zu `Column's, but the query returned only %zu columns!", + r->legacy_position + 1, column_num); + return (-ENOENT); + } + + /* Read `ds' and check number of values {{{ */ + r->ds = plugin_get_ds (r->type); + if (r->ds == NULL) + { + ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not " + "known by the daemon. See types.db(5) for details.", + r->type); + return (-1); + } + + if (r->ds->ds_num != 1) + { + ERROR ("db query utils: udb_result_prepare_result: The type `%s' " + "requires exactly %i values, but the legacy configuration " + "requires exactly one!", + r->type, + r->ds->ds_num); + return (-1); + } + /* }}} */ + + return (0); +} /* }}} int udb_legacy_result_prepare_result */ + +static int udb_legacy_result_create (const char *query_name, /* {{{ */ + udb_result_t **r_head, oconfig_item_t *ci, size_t position) +{ + udb_result_t *r; + + if ((ci->values_num < 1) || (ci->values_num > 2) + || (ci->values[0].type != OCONFIG_TYPE_STRING) + || ((ci->values_num == 2) + && (ci->values[1].type != OCONFIG_TYPE_STRING))) + { + WARNING ("db query utils: The `Column' block needs either one or two " + "string arguments."); + return (-1); + } + + r = (udb_result_t *) malloc (sizeof (*r)); + if (r == NULL) + { + ERROR ("db query utils: malloc failed."); + return (-1); + } + memset (r, 0, sizeof (*r)); + + r->legacy_mode = 1; + r->legacy_position = position; + + r->type = strdup (ci->values[0].value.string); + if (r->type == NULL) + { + ERROR ("db query utils: strdup failed."); + free (r); + return (-1); + } + + r->instance_prefix = NULL; + if (ci->values_num == 2) + { + r->instance_prefix = strdup (ci->values[1].value.string); + if (r->instance_prefix == NULL) + { + ERROR ("db query utils: strdup failed."); + free (r->type); + free (r); + return (-1); + } + } + + /* If all went well, add this result to the list of results. */ + if (*r_head == NULL) + { + *r_head = r; + } + else + { + udb_result_t *last; + + last = *r_head; + while (last->next != NULL) + last = last->next; + + last->next = r; + } + + return (0); +} /* }}} int udb_legacy_result_create */ + +/* * Result private functions */ static void udb_result_submit (udb_result_t *r, udb_query_t *q) /* {{{ */ @@ -178,6 +356,9 @@ static void udb_result_submit (udb_result_t *r, udb_query_t *q) /* {{{ */ value_list_t vl = VALUE_LIST_INIT; size_t i; + assert (r != NULL); + assert (r->legacy_mode == 0); + assert (r->ds != NULL); assert (((size_t) r->ds->ds_num) == r->values_num); DEBUG ("db query utils: udb_result_submit: r->instance_prefix = %s;", @@ -251,6 +432,14 @@ static void udb_result_finish_result (udb_result_t *r) /* {{{ */ if (r == NULL) return; + if (r->legacy_mode == 1) + { + udb_legacy_result_finish_result (r); + return; + } + + assert (r->legacy_mode == 0); + r->ds = NULL; sfree (r->instances_pos); sfree (r->values_pos); @@ -263,6 +452,11 @@ static int udb_result_handle_result (udb_result_t *r, /* {{{ */ { size_t i; + if (r->legacy_mode == 1) + return (udb_legacy_result_handle_result (r, q, column_values)); + + assert (r->legacy_mode == 0); + for (i = 0; i < r->instances_num; i++) r->instances_buffer[i] = column_values[r->instances_pos[i]]; @@ -282,6 +476,11 @@ static int udb_result_prepare_result (udb_result_t *r, /* {{{ */ if (r == NULL) return (-EINVAL); + if (r->legacy_mode == 1) + return (udb_legacy_result_prepare_result (r, column_names, column_num)); + + assert (r->legacy_mode == 0); + #define BAIL_OUT(status) \ r->ds = NULL; \ sfree (r->instances_pos); \ @@ -551,6 +750,8 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */ int status; int i; + size_t legacy_position; + if ((ret_query_list == NULL) || (ret_query_list_len == NULL)) return (-EINVAL); query_list = *ret_query_list; @@ -575,6 +776,8 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */ q->min_version = 0; q->max_version = UINT_MAX; + legacy_position = 0; + status = udb_config_set_string (&q->name, ci); if (status != 0) { @@ -605,6 +808,16 @@ int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */ q->name); status = udb_config_set_string (&q->statement, child); } + else if ((strcasecmp ("Column", child->key) == 0) + && (q->legacy_mode == 1)) + { + WARNING ("db query utils: Query `%s': The `Column' option is " + "deprecated. Please use the new syntax instead.", + q->name); + status = udb_legacy_result_create (q->name, &q->results, child, + legacy_position); + legacy_position++; + } else if ((strcasecmp ("MinPGVersion", child->key) == 0) && (q->legacy_mode == 1)) {