1 /**
2 * collectd - src/utils_db_query.c
3 * Copyright (C) 2008,2009 Florian octo Forster
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Florian octo Forster <octo at collectd.org>
25 **/
27 #include "collectd.h"
28 #include "common.h"
29 #include "plugin.h"
30 #include "configfile.h"
31 #include "utils_db_query.h"
33 /*
34 * Data types
35 */
36 struct udb_result_s; /* {{{ */
37 typedef struct udb_result_s udb_result_t;
38 struct udb_result_s
39 {
40 char *type;
41 char *instance_prefix;
42 char **instances;
43 size_t instances_num;
44 char **values;
45 size_t values_num;
47 udb_result_t *next;
48 }; /* }}} */
50 struct udb_query_s /* {{{ */
51 {
52 char *name;
53 char *statement;
54 void *user_data;
56 unsigned int min_version;
57 unsigned int max_version;
59 udb_result_t *results;
60 }; /* }}} */
62 struct udb_result_preparation_area_s /* {{{ */
63 {
64 const data_set_t *ds;
65 size_t *instances_pos;
66 size_t *values_pos;
67 char **instances_buffer;
68 char **values_buffer;
70 struct udb_result_preparation_area_s *next;
71 }; /* }}} */
72 typedef struct udb_result_preparation_area_s udb_result_preparation_area_t;
74 struct udb_query_preparation_area_s /* {{{ */
75 {
76 size_t column_num;
77 char *host;
78 char *plugin;
79 char *db_name;
81 cdtime_t interval;
83 udb_result_preparation_area_t *result_prep_areas;
84 }; /* }}} */
86 /*
87 * Config Private functions
88 */
89 static int udb_config_set_string (char **ret_string, /* {{{ */
90 oconfig_item_t *ci)
91 {
92 char *string;
94 if ((ci->values_num != 1)
95 || (ci->values[0].type != OCONFIG_TYPE_STRING))
96 {
97 WARNING ("db query utils: The `%s' config option "
98 "needs exactly one string argument.", ci->key);
99 return (-1);
100 }
102 string = strdup (ci->values[0].value.string);
103 if (string == NULL)
104 {
105 ERROR ("db query utils: strdup failed.");
106 return (-1);
107 }
109 if (*ret_string != NULL)
110 free (*ret_string);
111 *ret_string = string;
113 return (0);
114 } /* }}} int udb_config_set_string */
116 static int udb_config_add_string (char ***ret_array, /* {{{ */
117 size_t *ret_array_len, oconfig_item_t *ci)
118 {
119 char **array;
120 size_t array_len;
121 int i;
123 if (ci->values_num < 1)
124 {
125 WARNING ("db query utils: The `%s' config option "
126 "needs at least one argument.", ci->key);
127 return (-1);
128 }
130 for (i = 0; i < ci->values_num; i++)
131 {
132 if (ci->values[i].type != OCONFIG_TYPE_STRING)
133 {
134 WARNING ("db query utils: Argument %i to the `%s' option "
135 "is not a string.", i + 1, ci->key);
136 return (-1);
137 }
138 }
140 array_len = *ret_array_len;
141 array = (char **) realloc (*ret_array,
142 sizeof (char *) * (array_len + ci->values_num));
143 if (array == NULL)
144 {
145 ERROR ("db query utils: realloc failed.");
146 return (-1);
147 }
148 *ret_array = array;
150 for (i = 0; i < ci->values_num; i++)
151 {
152 array[array_len] = strdup (ci->values[i].value.string);
153 if (array[array_len] == NULL)
154 {
155 ERROR ("db query utils: strdup failed.");
156 *ret_array_len = array_len;
157 return (-1);
158 }
159 array_len++;
160 }
162 *ret_array_len = array_len;
163 return (0);
164 } /* }}} int udb_config_add_string */
166 static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
167 oconfig_item_t *ci)
168 {
169 double tmp;
171 if ((ci->values_num != 1)
172 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
173 {
174 WARNING ("db query utils: The `%s' config option "
175 "needs exactly one numeric argument.", ci->key);
176 return (-1);
177 }
179 tmp = ci->values[0].value.number;
180 if ((tmp < 0.0) || (tmp > ((double) UINT_MAX)))
181 return (-ERANGE);
183 *ret_value = (unsigned int) (tmp + .5);
184 return (0);
185 } /* }}} int udb_config_set_uint */
187 /*
188 * Result private functions
189 */
190 static int udb_result_submit (udb_result_t *r, /* {{{ */
191 udb_result_preparation_area_t *r_area,
192 udb_query_t const *q, udb_query_preparation_area_t *q_area)
193 {
194 value_list_t vl = VALUE_LIST_INIT;
195 size_t i;
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 plugin_dispatch_values (&vl);
263 sfree (vl.values);
264 return (0);
265 } /* }}} void udb_result_submit */
267 static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
268 udb_result_preparation_area_t *prep_area)
269 {
270 if ((r == NULL) || (prep_area == NULL))
271 return;
273 prep_area->ds = NULL;
274 sfree (prep_area->instances_pos);
275 sfree (prep_area->values_pos);
276 sfree (prep_area->instances_buffer);
277 sfree (prep_area->values_buffer);
278 } /* }}} void udb_result_finish_result */
280 static int udb_result_handle_result (udb_result_t *r, /* {{{ */
281 udb_query_preparation_area_t *q_area,
282 udb_result_preparation_area_t *r_area,
283 udb_query_t const *q, char **column_values)
284 {
285 size_t i;
287 assert (r && q_area && r_area);
289 for (i = 0; i < r->instances_num; i++)
290 r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
292 for (i = 0; i < r->values_num; i++)
293 r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
295 return udb_result_submit (r, r_area, q, q_area);
296 } /* }}} int udb_result_handle_result */
298 static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
299 udb_result_preparation_area_t *prep_area,
300 char **column_names, size_t column_num)
301 {
302 size_t i;
304 if ((r == NULL) || (prep_area == NULL))
305 return (-EINVAL);
307 #define BAIL_OUT(status) \
308 prep_area->ds = NULL; \
309 sfree (prep_area->instances_pos); \
310 sfree (prep_area->values_pos); \
311 sfree (prep_area->instances_buffer); \
312 sfree (prep_area->values_buffer); \
313 return (status)
315 /* Make sure previous preparations are cleaned up. */
316 udb_result_finish_result (r, prep_area);
317 prep_area->instances_pos = NULL;
318 prep_area->values_pos = NULL;
320 /* Read `ds' and check number of values {{{ */
321 prep_area->ds = plugin_get_ds (r->type);
322 if (prep_area->ds == NULL)
323 {
324 ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
325 "known by the daemon. See types.db(5) for details.",
326 r->type);
327 BAIL_OUT (-1);
328 }
330 if (((size_t) prep_area->ds->ds_num) != r->values_num)
331 {
332 ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
333 "requires exactly %i value%s, but the configuration specifies %zu.",
334 r->type,
335 prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
336 r->values_num);
337 BAIL_OUT (-1);
338 }
339 /* }}} */
341 /* Allocate r->instances_pos, r->values_pos, r->instances_buffer, and
342 * r->values_buffer {{{ */
343 if (r->instances_num > 0)
344 {
345 prep_area->instances_pos
346 = (size_t *) calloc (r->instances_num, sizeof (size_t));
347 if (prep_area->instances_pos == NULL)
348 {
349 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
350 BAIL_OUT (-ENOMEM);
351 }
353 prep_area->instances_buffer
354 = (char **) calloc (r->instances_num, sizeof (char *));
355 if (prep_area->instances_buffer == NULL)
356 {
357 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
358 BAIL_OUT (-ENOMEM);
359 }
360 } /* if (r->instances_num > 0) */
362 prep_area->values_pos
363 = (size_t *) calloc (r->values_num, sizeof (size_t));
364 if (prep_area->values_pos == NULL)
365 {
366 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
367 BAIL_OUT (-ENOMEM);
368 }
370 prep_area->values_buffer
371 = (char **) calloc (r->values_num, sizeof (char *));
372 if (prep_area->values_buffer == NULL)
373 {
374 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
375 BAIL_OUT (-ENOMEM);
376 }
377 /* }}} */
379 /* Determine the position of the instance columns {{{ */
380 for (i = 0; i < r->instances_num; i++)
381 {
382 size_t j;
384 for (j = 0; j < column_num; j++)
385 {
386 if (strcasecmp (r->instances[i], column_names[j]) == 0)
387 {
388 prep_area->instances_pos[i] = j;
389 break;
390 }
391 }
393 if (j >= column_num)
394 {
395 ERROR ("db query utils: udb_result_prepare_result: "
396 "Column `%s' could not be found.",
397 r->instances[i]);
398 BAIL_OUT (-ENOENT);
399 }
400 } /* }}} for (i = 0; i < r->instances_num; i++) */
402 /* Determine the position of the value columns {{{ */
403 for (i = 0; i < r->values_num; i++)
404 {
405 size_t j;
407 for (j = 0; j < column_num; j++)
408 {
409 if (strcasecmp (r->values[i], column_names[j]) == 0)
410 {
411 prep_area->values_pos[i] = j;
412 break;
413 }
414 }
416 if (j >= column_num)
417 {
418 ERROR ("db query utils: udb_result_prepare_result: "
419 "Column `%s' could not be found.",
420 r->values[i]);
421 BAIL_OUT (-ENOENT);
422 }
423 } /* }}} for (i = 0; i < r->values_num; i++) */
425 #undef BAIL_OUT
426 return (0);
427 } /* }}} int udb_result_prepare_result */
429 static void udb_result_free (udb_result_t *r) /* {{{ */
430 {
431 size_t i;
433 if (r == NULL)
434 return;
436 sfree (r->type);
438 for (i = 0; i < r->instances_num; i++)
439 sfree (r->instances[i]);
440 sfree (r->instances);
442 for (i = 0; i < r->values_num; i++)
443 sfree (r->values[i]);
444 sfree (r->values);
446 udb_result_free (r->next);
448 sfree (r);
449 } /* }}} void udb_result_free */
451 static int udb_result_create (const char *query_name, /* {{{ */
452 udb_result_t **r_head, oconfig_item_t *ci)
453 {
454 udb_result_t *r;
455 int status;
456 int i;
458 if (ci->values_num != 0)
459 {
460 WARNING ("db query utils: The `Result' block doesn't accept "
461 "any arguments. Ignoring %i argument%s.",
462 ci->values_num, (ci->values_num == 1) ? "" : "s");
463 }
465 r = (udb_result_t *) malloc (sizeof (*r));
466 if (r == NULL)
467 {
468 ERROR ("db query utils: malloc failed.");
469 return (-1);
470 }
471 memset (r, 0, sizeof (*r));
472 r->type = NULL;
473 r->instance_prefix = NULL;
474 r->instances = NULL;
475 r->values = NULL;
476 r->next = NULL;
478 /* Fill the `udb_result_t' structure.. */
479 status = 0;
480 for (i = 0; i < ci->children_num; i++)
481 {
482 oconfig_item_t *child = ci->children + i;
484 if (strcasecmp ("Type", child->key) == 0)
485 status = udb_config_set_string (&r->type, child);
486 else if (strcasecmp ("InstancePrefix", child->key) == 0)
487 status = udb_config_set_string (&r->instance_prefix, child);
488 else if (strcasecmp ("InstancesFrom", child->key) == 0)
489 status = udb_config_add_string (&r->instances, &r->instances_num, child);
490 else if (strcasecmp ("ValuesFrom", child->key) == 0)
491 status = udb_config_add_string (&r->values, &r->values_num, child);
492 else
493 {
494 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
495 query_name, child->key);
496 status = -1;
497 }
499 if (status != 0)
500 break;
501 }
503 /* Check that all necessary options have been given. */
504 while (status == 0)
505 {
506 if (r->type == NULL)
507 {
508 WARNING ("db query utils: `Type' not given for "
509 "result in query `%s'", query_name);
510 status = -1;
511 }
512 if (r->values == NULL)
513 {
514 WARNING ("db query utils: `ValuesFrom' not given for "
515 "result in query `%s'", query_name);
516 status = -1;
517 }
519 break;
520 } /* while (status == 0) */
522 if (status != 0)
523 {
524 udb_result_free (r);
525 return (-1);
526 }
528 /* If all went well, add this result to the list of results. */
529 if (*r_head == NULL)
530 {
531 *r_head = r;
532 }
533 else
534 {
535 udb_result_t *last;
537 last = *r_head;
538 while (last->next != NULL)
539 last = last->next;
541 last->next = r;
542 }
544 return (0);
545 } /* }}} int udb_result_create */
547 /*
548 * Query private functions
549 */
550 void udb_query_free_one (udb_query_t *q) /* {{{ */
551 {
552 if (q == NULL)
553 return;
555 sfree (q->name);
556 sfree (q->statement);
558 udb_result_free (q->results);
560 sfree (q);
561 } /* }}} void udb_query_free_one */
563 /*
564 * Query public functions
565 */
566 int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
567 size_t *ret_query_list_len, oconfig_item_t *ci,
568 udb_query_create_callback_t cb)
569 {
570 udb_query_t **query_list;
571 size_t query_list_len;
573 udb_query_t *q;
574 int status;
575 int i;
577 if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
578 return (-EINVAL);
579 query_list = *ret_query_list;
580 query_list_len = *ret_query_list_len;
582 if ((ci->values_num != 1)
583 || (ci->values[0].type != OCONFIG_TYPE_STRING))
584 {
585 WARNING ("db query utils: The `Query' block "
586 "needs exactly one string argument.");
587 return (-1);
588 }
590 q = (udb_query_t *) malloc (sizeof (*q));
591 if (q == NULL)
592 {
593 ERROR ("db query utils: malloc failed.");
594 return (-1);
595 }
596 memset (q, 0, sizeof (*q));
597 q->min_version = 0;
598 q->max_version = UINT_MAX;
600 status = udb_config_set_string (&q->name, ci);
601 if (status != 0)
602 {
603 sfree (q);
604 return (status);
605 }
607 /* Fill the `udb_query_t' structure.. */
608 for (i = 0; i < ci->children_num; i++)
609 {
610 oconfig_item_t *child = ci->children + i;
612 if (strcasecmp ("Statement", child->key) == 0)
613 status = udb_config_set_string (&q->statement, child);
614 else if (strcasecmp ("Result", child->key) == 0)
615 status = udb_result_create (q->name, &q->results, child);
616 else if (strcasecmp ("MinVersion", child->key) == 0)
617 status = udb_config_set_uint (&q->min_version, child);
618 else if (strcasecmp ("MaxVersion", child->key) == 0)
619 status = udb_config_set_uint (&q->max_version, child);
621 /* Call custom callbacks */
622 else if (cb != NULL)
623 {
624 status = (*cb) (q, child);
625 if (status != 0)
626 {
627 WARNING ("db query utils: The configuration callback failed "
628 "to handle `%s'.", child->key);
629 }
630 }
631 else
632 {
633 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
634 q->name, child->key);
635 status = -1;
636 }
638 if (status != 0)
639 break;
640 }
642 /* Check that all necessary options have been given. */
643 if (status == 0)
644 {
645 if (q->statement == NULL)
646 {
647 WARNING ("db query utils: Query `%s': No `Statement' given.", q->name);
648 status = -1;
649 }
650 if (q->results == NULL)
651 {
652 WARNING ("db query utils: Query `%s': No (valid) `Result' block given.",
653 q->name);
654 status = -1;
655 }
656 } /* if (status == 0) */
658 /* If all went well, add this query to the list of queries within the
659 * database structure. */
660 if (status == 0)
661 {
662 udb_query_t **temp;
664 temp = (udb_query_t **) realloc (query_list,
665 sizeof (*query_list) * (query_list_len + 1));
666 if (temp == NULL)
667 {
668 ERROR ("db query utils: realloc failed");
669 status = -1;
670 }
671 else
672 {
673 query_list = temp;
674 query_list[query_list_len] = q;
675 query_list_len++;
676 }
677 }
679 if (status != 0)
680 {
681 udb_query_free_one (q);
682 return (-1);
683 }
685 *ret_query_list = query_list;
686 *ret_query_list_len = query_list_len;
688 return (0);
689 } /* }}} int udb_query_create */
691 void udb_query_free (udb_query_t **query_list, size_t query_list_len) /* {{{ */
692 {
693 size_t i;
695 if (query_list == NULL)
696 return;
698 for (i = 0; i < query_list_len; i++)
699 udb_query_free_one (query_list[i]);
701 sfree (query_list);
702 } /* }}} void udb_query_free */
704 int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
705 udb_query_t **src_list, size_t src_list_len,
706 udb_query_t ***dst_list, size_t *dst_list_len)
707 {
708 size_t i;
709 int num_added;
711 if ((name == NULL) || (src_list == NULL) || (dst_list == NULL)
712 || (dst_list_len == NULL))
713 {
714 ERROR ("db query utils: udb_query_pick_from_list_by_name: "
715 "Invalid argument.");
716 return (-EINVAL);
717 }
719 num_added = 0;
720 for (i = 0; i < src_list_len; i++)
721 {
722 udb_query_t **tmp_list;
723 size_t tmp_list_len;
725 if (strcasecmp (name, src_list[i]->name) != 0)
726 continue;
728 tmp_list_len = *dst_list_len;
729 tmp_list = (udb_query_t **) realloc (*dst_list, (tmp_list_len + 1)
730 * sizeof (udb_query_t *));
731 if (tmp_list == NULL)
732 {
733 ERROR ("db query utils: realloc failed.");
734 return (-ENOMEM);
735 }
737 tmp_list[tmp_list_len] = src_list[i];
738 tmp_list_len++;
740 *dst_list = tmp_list;
741 *dst_list_len = tmp_list_len;
743 num_added++;
744 } /* for (i = 0; i < src_list_len; i++) */
746 if (num_added <= 0)
747 {
748 ERROR ("db query utils: Cannot find query `%s'. Make sure the <Query> "
749 "block is above the database definition!",
750 name);
751 return (-ENOENT);
752 }
753 else
754 {
755 DEBUG ("db query utils: Added %i versions of query `%s'.",
756 num_added, name);
757 }
759 return (0);
760 } /* }}} int udb_query_pick_from_list_by_name */
762 int udb_query_pick_from_list (oconfig_item_t *ci, /* {{{ */
763 udb_query_t **src_list, size_t src_list_len,
764 udb_query_t ***dst_list, size_t *dst_list_len)
765 {
766 const char *name;
768 if ((ci == NULL) || (src_list == NULL) || (dst_list == NULL)
769 || (dst_list_len == NULL))
770 {
771 ERROR ("db query utils: udb_query_pick_from_list: "
772 "Invalid argument.");
773 return (-EINVAL);
774 }
776 if ((ci->values_num != 1)
777 || (ci->values[0].type != OCONFIG_TYPE_STRING))
778 {
779 ERROR ("db query utils: The `%s' config option "
780 "needs exactly one string argument.", ci->key);
781 return (-1);
782 }
783 name = ci->values[0].value.string;
785 return (udb_query_pick_from_list_by_name (name,
786 src_list, src_list_len,
787 dst_list, dst_list_len));
788 } /* }}} int udb_query_pick_from_list */
790 const char *udb_query_get_name (udb_query_t *q) /* {{{ */
791 {
792 if (q == NULL)
793 return (NULL);
795 return (q->name);
796 } /* }}} const char *udb_query_get_name */
798 const char *udb_query_get_statement (udb_query_t *q) /* {{{ */
799 {
800 if (q == NULL)
801 return (NULL);
803 return (q->statement);
804 } /* }}} const char *udb_query_get_statement */
806 void udb_query_set_user_data (udb_query_t *q, void *user_data) /* {{{ */
807 {
808 if (q == NULL)
809 return;
811 q->user_data = user_data;
812 } /* }}} void udb_query_set_user_data */
814 void *udb_query_get_user_data (udb_query_t *q) /* {{{ */
815 {
816 if (q == NULL)
817 return (NULL);
819 return (q->user_data);
820 } /* }}} void *udb_query_get_user_data */
822 int udb_query_check_version (udb_query_t *q, unsigned int version) /* {{{ */
823 {
824 if (q == NULL)
825 return (-EINVAL);
827 if ((version < q->min_version) || (version > q->max_version))
828 return (0);
830 return (1);
831 } /* }}} int udb_query_check_version */
833 void udb_query_finish_result (udb_query_t const *q, /* {{{ */
834 udb_query_preparation_area_t *prep_area)
835 {
836 udb_result_preparation_area_t *r_area;
837 udb_result_t *r;
839 if ((q == NULL) || (prep_area == NULL))
840 return;
842 prep_area->column_num = 0;
843 sfree (prep_area->host);
844 sfree (prep_area->plugin);
845 sfree (prep_area->db_name);
847 prep_area->interval = 0;
849 for (r = q->results, r_area = prep_area->result_prep_areas;
850 r != NULL; r = r->next, r_area = r_area->next)
851 {
852 /* this may happen during error conditions of the caller */
853 if (r_area == NULL)
854 break;
855 udb_result_finish_result (r, r_area);
856 }
857 } /* }}} void udb_query_finish_result */
859 int udb_query_handle_result (udb_query_t const *q, /* {{{ */
860 udb_query_preparation_area_t *prep_area, char **column_values)
861 {
862 udb_result_preparation_area_t *r_area;
863 udb_result_t *r;
864 int success;
865 int status;
867 if ((q == NULL) || (prep_area == NULL))
868 return (-EINVAL);
870 if ((prep_area->column_num < 1) || (prep_area->host == NULL)
871 || (prep_area->plugin == NULL) || (prep_area->db_name == NULL))
872 {
873 ERROR ("db query utils: Query `%s': Query is not prepared; "
874 "can't handle result.", q->name);
875 return (-EINVAL);
876 }
878 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
879 do
880 {
881 size_t i;
883 for (i = 0; i < prep_area->column_num; i++)
884 {
885 DEBUG ("db query utils: udb_query_handle_result (%s, %s): "
886 "column[%zu] = %s;",
887 prep_area->db_name, q->name, i, column_values[i]);
888 }
889 } while (0);
890 #endif /* }}} */
892 success = 0;
893 for (r = q->results, r_area = prep_area->result_prep_areas;
894 r != NULL; r = r->next, r_area = r_area->next)
895 {
896 status = udb_result_handle_result (r, prep_area, r_area,
897 q, column_values);
898 if (status == 0)
899 success++;
900 }
902 if (success == 0)
903 {
904 ERROR ("db query utils: udb_query_handle_result (%s, %s): "
905 "All results failed.", prep_area->db_name, q->name);
906 return (-1);
907 }
909 return (0);
910 } /* }}} int udb_query_handle_result */
912 int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
913 udb_query_preparation_area_t *prep_area,
914 const char *host, const char *plugin, const char *db_name,
915 char **column_names, size_t column_num, cdtime_t interval)
916 {
917 udb_result_preparation_area_t *r_area;
918 udb_result_t *r;
919 int status;
921 if ((q == NULL) || (prep_area == NULL))
922 return (-EINVAL);
924 udb_query_finish_result (q, prep_area);
926 prep_area->column_num = column_num;
927 prep_area->host = strdup (host);
928 prep_area->plugin = strdup (plugin);
929 prep_area->db_name = strdup (db_name);
931 prep_area->interval = interval;
933 if ((prep_area->host == NULL) || (prep_area->plugin == NULL)
934 || (prep_area->db_name == NULL))
935 {
936 ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name);
937 udb_query_finish_result (q, prep_area);
938 return (-ENOMEM);
939 }
941 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
942 do
943 {
944 size_t i;
946 for (i = 0; i < column_num; i++)
947 {
948 DEBUG ("db query utils: udb_query_prepare_result: "
949 "query = %s; column[%zu] = %s;",
950 q->name, i, column_names[i]);
951 }
952 } while (0);
953 #endif
955 for (r = q->results, r_area = prep_area->result_prep_areas;
956 r != NULL; r = r->next, r_area = r_area->next)
957 {
958 if (! r_area)
959 {
960 ERROR ("db query utils: Query `%s': Invalid number of result "
961 "preparation areas.", q->name);
962 udb_query_finish_result (q, prep_area);
963 return (-EINVAL);
964 }
966 status = udb_result_prepare_result (r, r_area, column_names, column_num);
967 if (status != 0)
968 {
969 udb_query_finish_result (q, prep_area);
970 return (status);
971 }
972 }
974 return (0);
975 } /* }}} int udb_query_prepare_result */
977 udb_query_preparation_area_t *
978 udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */
979 {
980 udb_query_preparation_area_t *q_area;
981 udb_result_preparation_area_t **next_r_area;
982 udb_result_t *r;
984 q_area = (udb_query_preparation_area_t *)malloc (sizeof (*q_area));
985 if (q_area == NULL)
986 return NULL;
988 memset (q_area, 0, sizeof (*q_area));
990 next_r_area = &q_area->result_prep_areas;
991 for (r = q->results; r != NULL; r = r->next)
992 {
993 udb_result_preparation_area_t *r_area;
995 r_area = (udb_result_preparation_area_t *)malloc (sizeof (*r_area));
996 if (r_area == NULL)
997 {
998 for (r_area = q_area->result_prep_areas;
999 r_area != NULL; r_area = r_area->next)
1000 {
1001 free (r_area);
1002 }
1003 free (q_area);
1004 return NULL;
1005 }
1007 memset (r_area, 0, sizeof (*r_area));
1009 *next_r_area = r_area;
1010 next_r_area = &r_area->next;
1011 }
1013 return (q_area);
1014 } /* }}} udb_query_preparation_area_t *udb_query_allocate_preparation_area */
1016 void
1017 udb_query_delete_preparation_area (udb_query_preparation_area_t *q_area) /* {{{ */
1018 {
1019 udb_result_preparation_area_t *r_area;
1021 if (q_area == NULL)
1022 return;
1024 r_area = q_area->result_prep_areas;
1025 while (r_area != NULL)
1026 {
1027 udb_result_preparation_area_t *area = r_area;
1029 r_area = r_area->next;
1031 sfree (area->instances_pos);
1032 sfree (area->values_pos);
1033 sfree (area->instances_buffer);
1034 sfree (area->values_buffer);
1035 free (area);
1036 }
1038 sfree (q_area->host);
1039 sfree (q_area->plugin);
1040 sfree (q_area->db_name);
1042 free (q_area);
1043 } /* }}} void udb_query_delete_preparation_area */
1045 /* vim: set sw=2 sts=2 et fdm=marker : */