1 /**
2 * collectd - src/utils_db_query.c
3 * Copyright (C) 2008,2009 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Florian octo Forster <octo at verplant.org>
20 **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
26 #include "utils_db_query.h"
28 /*
29 * Data types
30 */
31 struct udb_result_s; /* {{{ */
32 typedef struct udb_result_s udb_result_t;
33 struct udb_result_s
34 {
35 char *type;
36 char *instance_prefix;
37 char **instances;
38 size_t instances_num;
39 char **values;
40 size_t values_num;
41 char **metadata;
42 size_t metadata_num;
44 udb_result_t *next;
45 }; /* }}} */
47 struct udb_query_s /* {{{ */
48 {
49 char *name;
50 char *statement;
51 void *user_data;
53 unsigned int min_version;
54 unsigned int max_version;
56 udb_result_t *results;
57 }; /* }}} */
59 struct udb_result_preparation_area_s /* {{{ */
60 {
61 const data_set_t *ds;
62 size_t *instances_pos;
63 size_t *values_pos;
64 size_t *metadata_pos;
65 char **instances_buffer;
66 char **values_buffer;
67 char **metadata_buffer;
69 struct udb_result_preparation_area_s *next;
70 }; /* }}} */
71 typedef struct udb_result_preparation_area_s udb_result_preparation_area_t;
73 struct udb_query_preparation_area_s /* {{{ */
74 {
75 size_t column_num;
76 char *host;
77 char *plugin;
78 char *db_name;
80 cdtime_t interval;
82 udb_result_preparation_area_t *result_prep_areas;
83 }; /* }}} */
85 /*
86 * Config Private functions
87 */
88 static int udb_config_set_string (char **ret_string, /* {{{ */
89 oconfig_item_t *ci)
90 {
91 char *string;
93 if ((ci->values_num != 1)
94 || (ci->values[0].type != OCONFIG_TYPE_STRING))
95 {
96 WARNING ("db query utils: The `%s' config option "
97 "needs exactly one string argument.", ci->key);
98 return (-1);
99 }
101 string = strdup (ci->values[0].value.string);
102 if (string == NULL)
103 {
104 ERROR ("db query utils: strdup failed.");
105 return (-1);
106 }
108 if (*ret_string != NULL)
109 free (*ret_string);
110 *ret_string = string;
112 return (0);
113 } /* }}} int udb_config_set_string */
115 static int udb_config_add_string (char ***ret_array, /* {{{ */
116 size_t *ret_array_len, oconfig_item_t *ci)
117 {
118 char **array;
119 size_t array_len;
120 int i;
122 if (ci->values_num < 1)
123 {
124 WARNING ("db query utils: The `%s' config option "
125 "needs at least one argument.", ci->key);
126 return (-1);
127 }
129 for (i = 0; i < ci->values_num; i++)
130 {
131 if (ci->values[i].type != OCONFIG_TYPE_STRING)
132 {
133 WARNING ("db query utils: Argument %i to the `%s' option "
134 "is not a string.", i + 1, ci->key);
135 return (-1);
136 }
137 }
139 array_len = *ret_array_len;
140 array = (char **) realloc (*ret_array,
141 sizeof (char *) * (array_len + ci->values_num));
142 if (array == NULL)
143 {
144 ERROR ("db query utils: realloc failed.");
145 return (-1);
146 }
147 *ret_array = array;
149 for (i = 0; i < ci->values_num; i++)
150 {
151 array[array_len] = strdup (ci->values[i].value.string);
152 if (array[array_len] == NULL)
153 {
154 ERROR ("db query utils: strdup failed.");
155 *ret_array_len = array_len;
156 return (-1);
157 }
158 array_len++;
159 }
161 *ret_array_len = array_len;
162 return (0);
163 } /* }}} int udb_config_add_string */
165 static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
166 oconfig_item_t *ci)
167 {
168 double tmp;
170 if ((ci->values_num != 1)
171 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
172 {
173 WARNING ("db query utils: The `%s' config option "
174 "needs exactly one numeric argument.", ci->key);
175 return (-1);
176 }
178 tmp = ci->values[0].value.number;
179 if ((tmp < 0.0) || (tmp > ((double) UINT_MAX)))
180 return (-ERANGE);
182 *ret_value = (unsigned int) (tmp + .5);
183 return (0);
184 } /* }}} int udb_config_set_uint */
186 /*
187 * Result private functions
188 */
189 static int udb_result_submit (udb_result_t *r, /* {{{ */
190 udb_result_preparation_area_t *r_area,
191 udb_query_t const *q, udb_query_preparation_area_t *q_area)
192 {
193 value_list_t vl = VALUE_LIST_INIT;
194 size_t i;
195 int status;
197 assert (r != NULL);
198 assert (r_area->ds != NULL);
199 assert (((size_t) r_area->ds->ds_num) == r->values_num);
201 vl.values = (value_t *) calloc (r_area->ds->ds_num, sizeof (value_t));
202 if (vl.values == NULL)
203 {
204 ERROR ("db query utils: malloc failed.");
205 return (-1);
206 }
207 vl.values_len = r_area->ds->ds_num;
209 for (i = 0; i < r->values_num; i++)
210 {
211 char *value_str = r_area->values_buffer[i];
213 if (0 != parse_value (value_str, &vl.values[i], r_area->ds->ds[i].type))
214 {
215 ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
216 value_str, DS_TYPE_TO_STRING (r_area->ds->ds[i].type));
217 errno = EINVAL;
218 return (-1);
219 }
220 }
222 if (q_area->interval > 0)
223 vl.interval = q_area->interval;
225 sstrncpy (vl.host, q_area->host, sizeof (vl.host));
226 sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
227 sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
228 sstrncpy (vl.type, r->type, sizeof (vl.type));
230 /* Set vl.type_instance {{{ */
231 if (r->instances_num <= 0)
232 {
233 if (r->instance_prefix == NULL)
234 vl.type_instance[0] = 0;
235 else
236 sstrncpy (vl.type_instance, r->instance_prefix,
237 sizeof (vl.type_instance));
238 }
239 else /* if ((r->instances_num > 0) */
240 {
241 if (r->instance_prefix == NULL)
242 {
243 strjoin (vl.type_instance, sizeof (vl.type_instance),
244 r_area->instances_buffer, r->instances_num, "-");
245 }
246 else
247 {
248 char tmp[DATA_MAX_NAME_LEN];
250 strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
251 r->instances_num, "-");
252 tmp[sizeof (tmp) - 1] = 0;
254 snprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
255 r->instance_prefix, tmp);
256 }
257 }
258 vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
259 /* }}} */
261 /* Annotate meta data. {{{ */
262 if (r->metadata_num > 0)
263 {
264 vl.meta = meta_data_create ();
265 if (vl.meta == NULL)
266 {
267 ERROR ("db query utils:: meta_data_create failed.");
268 return (-ENOMEM);
269 }
271 for (i = 0; i < r->metadata_num; i++)
272 {
273 status = meta_data_add_string (vl.meta, r->metadata[i],
274 r_area->metadata_buffer[i]);
275 if (status != 0)
276 {
277 ERROR ("db query utils:: meta_data_add_string failed.");
278 meta_data_destroy (vl.meta);
279 vl.meta = NULL;
280 return (status);
281 }
282 }
283 }
284 /* }}} */
286 plugin_dispatch_values (&vl);
288 if (r->metadata_num > 0)
289 {
290 meta_data_destroy (vl.meta);
291 vl.meta = NULL;
292 }
293 sfree (vl.values);
294 return (0);
295 } /* }}} void udb_result_submit */
297 static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
298 udb_result_preparation_area_t *prep_area)
299 {
300 if ((r == NULL) || (prep_area == NULL))
301 return;
303 prep_area->ds = NULL;
304 sfree (prep_area->instances_pos);
305 sfree (prep_area->values_pos);
306 sfree (prep_area->metadata_pos);
307 sfree (prep_area->instances_buffer);
308 sfree (prep_area->values_buffer);
309 sfree (prep_area->metadata_buffer);
310 } /* }}} void udb_result_finish_result */
312 static int udb_result_handle_result (udb_result_t *r, /* {{{ */
313 udb_query_preparation_area_t *q_area,
314 udb_result_preparation_area_t *r_area,
315 udb_query_t const *q, char **column_values)
316 {
317 size_t i;
319 assert (r && q_area && r_area);
321 for (i = 0; i < r->instances_num; i++)
322 r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
324 for (i = 0; i < r->values_num; i++)
325 r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
327 for (i = 0; i < r->metadata_num; i++)
328 r_area->metadata_buffer[i] = column_values[r_area->metadata_pos[i]];
330 return udb_result_submit (r, r_area, q, q_area);
331 } /* }}} int udb_result_handle_result */
333 static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
334 udb_result_preparation_area_t *prep_area,
335 char **column_names, size_t column_num)
336 {
337 size_t i;
339 if ((r == NULL) || (prep_area == NULL))
340 return (-EINVAL);
342 #define BAIL_OUT(status) \
343 prep_area->ds = NULL; \
344 sfree (prep_area->instances_pos); \
345 sfree (prep_area->values_pos); \
346 sfree (prep_area->metadata_pos); \
347 sfree (prep_area->instances_buffer); \
348 sfree (prep_area->values_buffer); \
349 sfree (prep_area->metadata_buffer); \
350 return (status)
352 /* Make sure previous preparations are cleaned up. */
353 udb_result_finish_result (r, prep_area);
354 prep_area->instances_pos = NULL;
355 prep_area->values_pos = NULL;
356 prep_area->metadata_pos = NULL;
358 /* Read `ds' and check number of values {{{ */
359 prep_area->ds = plugin_get_ds (r->type);
360 if (prep_area->ds == NULL)
361 {
362 ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
363 "known by the daemon. See types.db(5) for details.",
364 r->type);
365 BAIL_OUT (-1);
366 }
368 if (((size_t) prep_area->ds->ds_num) != r->values_num)
369 {
370 ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
371 "requires exactly %i value%s, but the configuration specifies %zu.",
372 r->type,
373 prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
374 r->values_num);
375 BAIL_OUT (-1);
376 }
377 /* }}} */
379 /* Allocate r->instances_pos, r->values_pos, r->metadata_post,
380 * r->instances_buffer, r->values_buffer, and r->metadata_buffer {{{ */
381 if (r->instances_num > 0)
382 {
383 prep_area->instances_pos
384 = (size_t *) calloc (r->instances_num, sizeof (size_t));
385 if (prep_area->instances_pos == NULL)
386 {
387 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
388 BAIL_OUT (-ENOMEM);
389 }
391 prep_area->instances_buffer
392 = (char **) calloc (r->instances_num, sizeof (char *));
393 if (prep_area->instances_buffer == NULL)
394 {
395 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
396 BAIL_OUT (-ENOMEM);
397 }
398 } /* if (r->instances_num > 0) */
400 prep_area->values_pos
401 = (size_t *) calloc (r->values_num, sizeof (size_t));
402 if (prep_area->values_pos == NULL)
403 {
404 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
405 BAIL_OUT (-ENOMEM);
406 }
408 prep_area->values_buffer
409 = (char **) calloc (r->values_num, sizeof (char *));
410 if (prep_area->values_buffer == NULL)
411 {
412 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
413 BAIL_OUT (-ENOMEM);
414 }
416 prep_area->metadata_pos
417 = (size_t *) calloc (r->metadata_num, sizeof (size_t));
418 if (prep_area->metadata_pos == NULL)
419 {
420 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
421 BAIL_OUT (-ENOMEM);
422 }
424 prep_area->metadata_buffer
425 = (char **) calloc (r->metadata_num, sizeof (char *));
426 if (prep_area->metadata_buffer == NULL)
427 {
428 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
429 BAIL_OUT (-ENOMEM);
430 }
432 /* }}} */
434 /* Determine the position of the instance columns {{{ */
435 for (i = 0; i < r->instances_num; i++)
436 {
437 size_t j;
439 for (j = 0; j < column_num; j++)
440 {
441 if (strcasecmp (r->instances[i], column_names[j]) == 0)
442 {
443 prep_area->instances_pos[i] = j;
444 break;
445 }
446 }
448 if (j >= column_num)
449 {
450 ERROR ("db query utils: udb_result_prepare_result: "
451 "Column `%s' could not be found.",
452 r->instances[i]);
453 BAIL_OUT (-ENOENT);
454 }
455 } /* }}} for (i = 0; i < r->instances_num; i++) */
457 /* Determine the position of the value columns {{{ */
458 for (i = 0; i < r->values_num; i++)
459 {
460 size_t j;
462 for (j = 0; j < column_num; j++)
463 {
464 if (strcasecmp (r->values[i], column_names[j]) == 0)
465 {
466 prep_area->values_pos[i] = j;
467 break;
468 }
469 }
471 if (j >= column_num)
472 {
473 ERROR ("db query utils: udb_result_prepare_result: "
474 "Column `%s' could not be found.",
475 r->values[i]);
476 BAIL_OUT (-ENOENT);
477 }
478 } /* }}} for (i = 0; i < r->values_num; i++) */
480 /* Determine the position of the metadata columns {{{ */
481 for (i = 0; i < r->metadata_num; i++)
482 {
483 size_t j;
485 for (j = 0; j < column_num; j++)
486 {
487 if (strcasecmp (r->metadata[i], column_names[j]) == 0)
488 {
489 prep_area->metadata_pos[i] = j;
490 break;
491 }
492 }
494 if (j >= column_num)
495 {
496 ERROR ("db query utils: udb_result_prepare_result: "
497 "Metadata column `%s' could not be found.",
498 r->values[i]);
499 BAIL_OUT (-ENOENT);
500 }
501 } /* }}} for (i = 0; i < r->metadata_num; i++) */
503 #undef BAIL_OUT
504 return (0);
505 } /* }}} int udb_result_prepare_result */
507 static void udb_result_free (udb_result_t *r) /* {{{ */
508 {
509 size_t i;
511 if (r == NULL)
512 return;
514 sfree (r->type);
516 for (i = 0; i < r->instances_num; i++)
517 sfree (r->instances[i]);
518 sfree (r->instances);
520 for (i = 0; i < r->values_num; i++)
521 sfree (r->values[i]);
522 sfree (r->values);
524 for (i = 0; i < r->metadata_num; i++)
525 sfree (r->metadata[i]);
526 sfree (r->metadata);
528 udb_result_free (r->next);
530 sfree (r);
531 } /* }}} void udb_result_free */
533 static int udb_result_create (const char *query_name, /* {{{ */
534 udb_result_t **r_head, oconfig_item_t *ci)
535 {
536 udb_result_t *r;
537 int status;
538 int i;
540 if (ci->values_num != 0)
541 {
542 WARNING ("db query utils: The `Result' block doesn't accept "
543 "any arguments. Ignoring %i argument%s.",
544 ci->values_num, (ci->values_num == 1) ? "" : "s");
545 }
547 r = (udb_result_t *) malloc (sizeof (*r));
548 if (r == NULL)
549 {
550 ERROR ("db query utils: malloc failed.");
551 return (-1);
552 }
553 memset (r, 0, sizeof (*r));
554 r->type = NULL;
555 r->instance_prefix = NULL;
556 r->instances = NULL;
557 r->values = NULL;
558 r->metadata = NULL;
559 r->next = NULL;
561 /* Fill the `udb_result_t' structure.. */
562 status = 0;
563 for (i = 0; i < ci->children_num; i++)
564 {
565 oconfig_item_t *child = ci->children + i;
567 if (strcasecmp ("Type", child->key) == 0)
568 status = udb_config_set_string (&r->type, child);
569 else if (strcasecmp ("InstancePrefix", child->key) == 0)
570 status = udb_config_set_string (&r->instance_prefix, child);
571 else if (strcasecmp ("InstancesFrom", child->key) == 0)
572 status = udb_config_add_string (&r->instances, &r->instances_num, child);
573 else if (strcasecmp ("ValuesFrom", child->key) == 0)
574 status = udb_config_add_string (&r->values, &r->values_num, child);
575 else if (strcasecmp ("MetadataFrom", child->key) == 0)
576 status = udb_config_add_string (&r->metadata, &r->metadata_num, child);
577 else
578 {
579 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
580 query_name, child->key);
581 status = -1;
582 }
584 if (status != 0)
585 break;
586 }
588 /* Check that all necessary options have been given. */
589 while (status == 0)
590 {
591 if (r->type == NULL)
592 {
593 WARNING ("db query utils: `Type' not given for "
594 "result in query `%s'", query_name);
595 status = -1;
596 }
597 if (r->values == NULL)
598 {
599 WARNING ("db query utils: `ValuesFrom' not given for "
600 "result in query `%s'", query_name);
601 status = -1;
602 }
604 break;
605 } /* while (status == 0) */
607 if (status != 0)
608 {
609 udb_result_free (r);
610 return (-1);
611 }
613 /* If all went well, add this result to the list of results. */
614 if (*r_head == NULL)
615 {
616 *r_head = r;
617 }
618 else
619 {
620 udb_result_t *last;
622 last = *r_head;
623 while (last->next != NULL)
624 last = last->next;
626 last->next = r;
627 }
629 return (0);
630 } /* }}} int udb_result_create */
632 /*
633 * Query private functions
634 */
635 void udb_query_free_one (udb_query_t *q) /* {{{ */
636 {
637 if (q == NULL)
638 return;
640 sfree (q->name);
641 sfree (q->statement);
643 udb_result_free (q->results);
645 sfree (q);
646 } /* }}} void udb_query_free_one */
648 /*
649 * Query public functions
650 */
651 int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
652 size_t *ret_query_list_len, oconfig_item_t *ci,
653 udb_query_create_callback_t cb)
654 {
655 udb_query_t **query_list;
656 size_t query_list_len;
658 udb_query_t *q;
659 int status;
660 int i;
662 if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
663 return (-EINVAL);
664 query_list = *ret_query_list;
665 query_list_len = *ret_query_list_len;
667 if ((ci->values_num != 1)
668 || (ci->values[0].type != OCONFIG_TYPE_STRING))
669 {
670 WARNING ("db query utils: The `Query' block "
671 "needs exactly one string argument.");
672 return (-1);
673 }
675 q = (udb_query_t *) malloc (sizeof (*q));
676 if (q == NULL)
677 {
678 ERROR ("db query utils: malloc failed.");
679 return (-1);
680 }
681 memset (q, 0, sizeof (*q));
682 q->min_version = 0;
683 q->max_version = UINT_MAX;
685 status = udb_config_set_string (&q->name, ci);
686 if (status != 0)
687 {
688 sfree (q);
689 return (status);
690 }
692 /* Fill the `udb_query_t' structure.. */
693 for (i = 0; i < ci->children_num; i++)
694 {
695 oconfig_item_t *child = ci->children + i;
697 if (strcasecmp ("Statement", child->key) == 0)
698 status = udb_config_set_string (&q->statement, child);
699 else if (strcasecmp ("Result", child->key) == 0)
700 status = udb_result_create (q->name, &q->results, child);
701 else if (strcasecmp ("MinVersion", child->key) == 0)
702 status = udb_config_set_uint (&q->min_version, child);
703 else if (strcasecmp ("MaxVersion", child->key) == 0)
704 status = udb_config_set_uint (&q->max_version, child);
706 /* Call custom callbacks */
707 else if (cb != NULL)
708 {
709 status = (*cb) (q, child);
710 if (status != 0)
711 {
712 WARNING ("db query utils: The configuration callback failed "
713 "to handle `%s'.", child->key);
714 }
715 }
716 else
717 {
718 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
719 q->name, child->key);
720 status = -1;
721 }
723 if (status != 0)
724 break;
725 }
727 /* Check that all necessary options have been given. */
728 if (status == 0)
729 {
730 if (q->statement == NULL)
731 {
732 WARNING ("db query utils: Query `%s': No `Statement' given.", q->name);
733 status = -1;
734 }
735 if (q->results == NULL)
736 {
737 WARNING ("db query utils: Query `%s': No (valid) `Result' block given.",
738 q->name);
739 status = -1;
740 }
741 } /* if (status == 0) */
743 /* If all went well, add this query to the list of queries within the
744 * database structure. */
745 if (status == 0)
746 {
747 udb_query_t **temp;
749 temp = (udb_query_t **) realloc (query_list,
750 sizeof (*query_list) * (query_list_len + 1));
751 if (temp == NULL)
752 {
753 ERROR ("db query utils: realloc failed");
754 status = -1;
755 }
756 else
757 {
758 query_list = temp;
759 query_list[query_list_len] = q;
760 query_list_len++;
761 }
762 }
764 if (status != 0)
765 {
766 udb_query_free_one (q);
767 return (-1);
768 }
770 *ret_query_list = query_list;
771 *ret_query_list_len = query_list_len;
773 return (0);
774 } /* }}} int udb_query_create */
776 void udb_query_free (udb_query_t **query_list, size_t query_list_len) /* {{{ */
777 {
778 size_t i;
780 if (query_list == NULL)
781 return;
783 for (i = 0; i < query_list_len; i++)
784 udb_query_free_one (query_list[i]);
786 sfree (query_list);
787 } /* }}} void udb_query_free */
789 int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
790 udb_query_t **src_list, size_t src_list_len,
791 udb_query_t ***dst_list, size_t *dst_list_len)
792 {
793 size_t i;
794 int num_added;
796 if ((name == NULL) || (src_list == NULL) || (dst_list == NULL)
797 || (dst_list_len == NULL))
798 {
799 ERROR ("db query utils: udb_query_pick_from_list_by_name: "
800 "Invalid argument.");
801 return (-EINVAL);
802 }
804 num_added = 0;
805 for (i = 0; i < src_list_len; i++)
806 {
807 udb_query_t **tmp_list;
808 size_t tmp_list_len;
810 if (strcasecmp (name, src_list[i]->name) != 0)
811 continue;
813 tmp_list_len = *dst_list_len;
814 tmp_list = (udb_query_t **) realloc (*dst_list, (tmp_list_len + 1)
815 * sizeof (udb_query_t *));
816 if (tmp_list == NULL)
817 {
818 ERROR ("db query utils: realloc failed.");
819 return (-ENOMEM);
820 }
822 tmp_list[tmp_list_len] = src_list[i];
823 tmp_list_len++;
825 *dst_list = tmp_list;
826 *dst_list_len = tmp_list_len;
828 num_added++;
829 } /* for (i = 0; i < src_list_len; i++) */
831 if (num_added <= 0)
832 {
833 ERROR ("db query utils: Cannot find query `%s'. Make sure the <Query> "
834 "block is above the database definition!",
835 name);
836 return (-ENOENT);
837 }
838 else
839 {
840 DEBUG ("db query utils: Added %i versions of query `%s'.",
841 num_added, name);
842 }
844 return (0);
845 } /* }}} int udb_query_pick_from_list_by_name */
847 int udb_query_pick_from_list (oconfig_item_t *ci, /* {{{ */
848 udb_query_t **src_list, size_t src_list_len,
849 udb_query_t ***dst_list, size_t *dst_list_len)
850 {
851 const char *name;
853 if ((ci == NULL) || (src_list == NULL) || (dst_list == NULL)
854 || (dst_list_len == NULL))
855 {
856 ERROR ("db query utils: udb_query_pick_from_list: "
857 "Invalid argument.");
858 return (-EINVAL);
859 }
861 if ((ci->values_num != 1)
862 || (ci->values[0].type != OCONFIG_TYPE_STRING))
863 {
864 ERROR ("db query utils: The `%s' config option "
865 "needs exactly one string argument.", ci->key);
866 return (-1);
867 }
868 name = ci->values[0].value.string;
870 return (udb_query_pick_from_list_by_name (name,
871 src_list, src_list_len,
872 dst_list, dst_list_len));
873 } /* }}} int udb_query_pick_from_list */
875 const char *udb_query_get_name (udb_query_t *q) /* {{{ */
876 {
877 if (q == NULL)
878 return (NULL);
880 return (q->name);
881 } /* }}} const char *udb_query_get_name */
883 const char *udb_query_get_statement (udb_query_t *q) /* {{{ */
884 {
885 if (q == NULL)
886 return (NULL);
888 return (q->statement);
889 } /* }}} const char *udb_query_get_statement */
891 void udb_query_set_user_data (udb_query_t *q, void *user_data) /* {{{ */
892 {
893 if (q == NULL)
894 return;
896 q->user_data = user_data;
897 } /* }}} void udb_query_set_user_data */
899 void *udb_query_get_user_data (udb_query_t *q) /* {{{ */
900 {
901 if (q == NULL)
902 return (NULL);
904 return (q->user_data);
905 } /* }}} void *udb_query_get_user_data */
907 int udb_query_check_version (udb_query_t *q, unsigned int version) /* {{{ */
908 {
909 if (q == NULL)
910 return (-EINVAL);
912 if ((version < q->min_version) || (version > q->max_version))
913 return (0);
915 return (1);
916 } /* }}} int udb_query_check_version */
918 void udb_query_finish_result (udb_query_t const *q, /* {{{ */
919 udb_query_preparation_area_t *prep_area)
920 {
921 udb_result_preparation_area_t *r_area;
922 udb_result_t *r;
924 if ((q == NULL) || (prep_area == NULL))
925 return;
927 prep_area->column_num = 0;
928 sfree (prep_area->host);
929 sfree (prep_area->plugin);
930 sfree (prep_area->db_name);
932 prep_area->interval = 0;
934 for (r = q->results, r_area = prep_area->result_prep_areas;
935 r != NULL; r = r->next, r_area = r_area->next)
936 {
937 /* this may happen during error conditions of the caller */
938 if (r_area == NULL)
939 break;
940 udb_result_finish_result (r, r_area);
941 }
942 } /* }}} void udb_query_finish_result */
944 int udb_query_handle_result (udb_query_t const *q, /* {{{ */
945 udb_query_preparation_area_t *prep_area, char **column_values)
946 {
947 udb_result_preparation_area_t *r_area;
948 udb_result_t *r;
949 int success;
950 int status;
952 if ((q == NULL) || (prep_area == NULL))
953 return (-EINVAL);
955 if ((prep_area->column_num < 1) || (prep_area->host == NULL)
956 || (prep_area->plugin == NULL) || (prep_area->db_name == NULL))
957 {
958 ERROR ("db query utils: Query `%s': Query is not prepared; "
959 "can't handle result.", q->name);
960 return (-EINVAL);
961 }
963 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
964 do
965 {
966 size_t i;
968 for (i = 0; i < prep_area->column_num; i++)
969 {
970 DEBUG ("db query utils: udb_query_handle_result (%s, %s): "
971 "column[%zu] = %s;",
972 prep_area->db_name, q->name, i, column_values[i]);
973 }
974 } while (0);
975 #endif /* }}} */
977 success = 0;
978 for (r = q->results, r_area = prep_area->result_prep_areas;
979 r != NULL; r = r->next, r_area = r_area->next)
980 {
981 status = udb_result_handle_result (r, prep_area, r_area,
982 q, column_values);
983 if (status == 0)
984 success++;
985 }
987 if (success == 0)
988 {
989 ERROR ("db query utils: udb_query_handle_result (%s, %s): "
990 "All results failed.", prep_area->db_name, q->name);
991 return (-1);
992 }
994 return (0);
995 } /* }}} int udb_query_handle_result */
997 int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
998 udb_query_preparation_area_t *prep_area,
999 const char *host, const char *plugin, const char *db_name,
1000 char **column_names, size_t column_num, cdtime_t interval)
1001 {
1002 udb_result_preparation_area_t *r_area;
1003 udb_result_t *r;
1004 int status;
1006 if ((q == NULL) || (prep_area == NULL))
1007 return (-EINVAL);
1009 udb_query_finish_result (q, prep_area);
1011 prep_area->column_num = column_num;
1012 prep_area->host = strdup (host);
1013 prep_area->plugin = strdup (plugin);
1014 prep_area->db_name = strdup (db_name);
1016 prep_area->interval = interval;
1018 if ((prep_area->host == NULL) || (prep_area->plugin == NULL)
1019 || (prep_area->db_name == NULL))
1020 {
1021 ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name);
1022 udb_query_finish_result (q, prep_area);
1023 return (-ENOMEM);
1024 }
1026 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
1027 do
1028 {
1029 size_t i;
1031 for (i = 0; i < column_num; i++)
1032 {
1033 DEBUG ("db query utils: udb_query_prepare_result: "
1034 "query = %s; column[%zu] = %s;",
1035 q->name, i, column_names[i]);
1036 }
1037 } while (0);
1038 #endif
1040 for (r = q->results, r_area = prep_area->result_prep_areas;
1041 r != NULL; r = r->next, r_area = r_area->next)
1042 {
1043 if (! r_area)
1044 {
1045 ERROR ("db query utils: Query `%s': Invalid number of result "
1046 "preparation areas.", q->name);
1047 udb_query_finish_result (q, prep_area);
1048 return (-EINVAL);
1049 }
1051 status = udb_result_prepare_result (r, r_area, column_names, column_num);
1052 if (status != 0)
1053 {
1054 udb_query_finish_result (q, prep_area);
1055 return (status);
1056 }
1057 }
1059 return (0);
1060 } /* }}} int udb_query_prepare_result */
1062 udb_query_preparation_area_t *
1063 udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */
1064 {
1065 udb_query_preparation_area_t *q_area;
1066 udb_result_preparation_area_t **next_r_area;
1067 udb_result_t *r;
1069 q_area = (udb_query_preparation_area_t *)malloc (sizeof (*q_area));
1070 if (q_area == NULL)
1071 return NULL;
1073 memset (q_area, 0, sizeof (*q_area));
1075 next_r_area = &q_area->result_prep_areas;
1076 for (r = q->results; r != NULL; r = r->next)
1077 {
1078 udb_result_preparation_area_t *r_area;
1080 r_area = (udb_result_preparation_area_t *)malloc (sizeof (*r_area));
1081 if (r_area == NULL)
1082 {
1083 for (r_area = q_area->result_prep_areas;
1084 r_area != NULL; r_area = r_area->next)
1085 {
1086 free (r_area);
1087 }
1088 free (q_area);
1089 return NULL;
1090 }
1092 memset (r_area, 0, sizeof (*r_area));
1094 *next_r_area = r_area;
1095 next_r_area = &r_area->next;
1096 }
1098 return (q_area);
1099 } /* }}} udb_query_preparation_area_t *udb_query_allocate_preparation_area */
1101 void
1102 udb_query_delete_preparation_area (udb_query_preparation_area_t *q_area) /* {{{ */
1103 {
1104 udb_result_preparation_area_t *r_area;
1106 if (q_area == NULL)
1107 return;
1109 r_area = q_area->result_prep_areas;
1110 while (r_area != NULL)
1111 {
1112 udb_result_preparation_area_t *area = r_area;
1114 r_area = r_area->next;
1116 sfree (area->instances_pos);
1117 sfree (area->values_pos);
1118 sfree (area->instances_buffer);
1119 sfree (area->values_buffer);
1120 free (area);
1121 }
1123 sfree (q_area->host);
1124 sfree (q_area->plugin);
1125 sfree (q_area->db_name);
1127 free (q_area);
1128 } /* }}} void udb_query_delete_preparation_area */
1130 /* vim: set sw=2 sts=2 et fdm=marker : */