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;
42 udb_result_t *next;
43 }; /* }}} */
45 struct udb_query_s /* {{{ */
46 {
47 char *name;
48 char *statement;
49 void *user_data;
51 unsigned int min_version;
52 unsigned int max_version;
54 udb_result_t *results;
55 }; /* }}} */
57 struct udb_result_preparation_area_s /* {{{ */
58 {
59 const data_set_t *ds;
60 size_t *instances_pos;
61 size_t *values_pos;
62 char **instances_buffer;
63 char **values_buffer;
65 struct udb_result_preparation_area_s *next;
66 }; /* }}} */
67 typedef struct udb_result_preparation_area_s udb_result_preparation_area_t;
69 struct udb_query_preparation_area_s /* {{{ */
70 {
71 size_t column_num;
72 char *host;
73 char *plugin;
74 char *db_name;
76 cdtime_t interval;
78 udb_result_preparation_area_t *result_prep_areas;
79 }; /* }}} */
81 /*
82 * Config Private functions
83 */
84 static int udb_config_set_string (char **ret_string, /* {{{ */
85 oconfig_item_t *ci)
86 {
87 char *string;
89 if ((ci->values_num != 1)
90 || (ci->values[0].type != OCONFIG_TYPE_STRING))
91 {
92 WARNING ("db query utils: The `%s' config option "
93 "needs exactly one string argument.", ci->key);
94 return (-1);
95 }
97 string = strdup (ci->values[0].value.string);
98 if (string == NULL)
99 {
100 ERROR ("db query utils: strdup failed.");
101 return (-1);
102 }
104 if (*ret_string != NULL)
105 free (*ret_string);
106 *ret_string = string;
108 return (0);
109 } /* }}} int udb_config_set_string */
111 static int udb_config_add_string (char ***ret_array, /* {{{ */
112 size_t *ret_array_len, oconfig_item_t *ci)
113 {
114 char **array;
115 size_t array_len;
116 int i;
118 if (ci->values_num < 1)
119 {
120 WARNING ("db query utils: The `%s' config option "
121 "needs at least one argument.", ci->key);
122 return (-1);
123 }
125 for (i = 0; i < ci->values_num; i++)
126 {
127 if (ci->values[i].type != OCONFIG_TYPE_STRING)
128 {
129 WARNING ("db query utils: Argument %i to the `%s' option "
130 "is not a string.", i + 1, ci->key);
131 return (-1);
132 }
133 }
135 array_len = *ret_array_len;
136 array = (char **) realloc (*ret_array,
137 sizeof (char *) * (array_len + ci->values_num));
138 if (array == NULL)
139 {
140 ERROR ("db query utils: realloc failed.");
141 return (-1);
142 }
143 *ret_array = array;
145 for (i = 0; i < ci->values_num; i++)
146 {
147 array[array_len] = strdup (ci->values[i].value.string);
148 if (array[array_len] == NULL)
149 {
150 ERROR ("db query utils: strdup failed.");
151 *ret_array_len = array_len;
152 return (-1);
153 }
154 array_len++;
155 }
157 *ret_array_len = array_len;
158 return (0);
159 } /* }}} int udb_config_add_string */
161 static int udb_config_set_uint (unsigned int *ret_value, /* {{{ */
162 oconfig_item_t *ci)
163 {
164 double tmp;
166 if ((ci->values_num != 1)
167 || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
168 {
169 WARNING ("db query utils: The `%s' config option "
170 "needs exactly one numeric argument.", ci->key);
171 return (-1);
172 }
174 tmp = ci->values[0].value.number;
175 if ((tmp < 0.0) || (tmp > ((double) UINT_MAX)))
176 return (-ERANGE);
178 *ret_value = (unsigned int) (tmp + .5);
179 return (0);
180 } /* }}} int udb_config_set_uint */
182 /*
183 * Result private functions
184 */
185 static int udb_result_submit (udb_result_t *r, /* {{{ */
186 udb_result_preparation_area_t *r_area,
187 udb_query_t const *q, udb_query_preparation_area_t *q_area)
188 {
189 value_list_t vl = VALUE_LIST_INIT;
190 size_t i;
192 assert (r != NULL);
193 assert (r_area->ds != NULL);
194 assert (((size_t) r_area->ds->ds_num) == r->values_num);
195 assert (r->values_num > 0);
197 vl.values = (value_t *) calloc (r->values_num, sizeof (value_t));
198 if (vl.values == NULL)
199 {
200 ERROR ("db query utils: malloc failed.");
201 return (-1);
202 }
203 vl.values_len = r_area->ds->ds_num;
205 for (i = 0; i < r->values_num; i++)
206 {
207 char *value_str = r_area->values_buffer[i];
209 if (0 != parse_value (value_str, &vl.values[i], r_area->ds->ds[i].type))
210 {
211 ERROR ("db query utils: udb_result_submit: Parsing `%s' as %s failed.",
212 value_str, DS_TYPE_TO_STRING (r_area->ds->ds[i].type));
213 errno = EINVAL;
214 return (-1);
215 }
216 }
218 if (q_area->interval > 0)
219 vl.interval = q_area->interval;
221 sstrncpy (vl.host, q_area->host, sizeof (vl.host));
222 sstrncpy (vl.plugin, q_area->plugin, sizeof (vl.plugin));
223 sstrncpy (vl.plugin_instance, q_area->db_name, sizeof (vl.plugin_instance));
224 sstrncpy (vl.type, r->type, sizeof (vl.type));
226 /* Set vl.type_instance {{{ */
227 if (r->instances_num <= 0)
228 {
229 if (r->instance_prefix == NULL)
230 vl.type_instance[0] = 0;
231 else
232 sstrncpy (vl.type_instance, r->instance_prefix,
233 sizeof (vl.type_instance));
234 }
235 else /* if ((r->instances_num > 0) */
236 {
237 if (r->instance_prefix == NULL)
238 {
239 int status = strjoin (vl.type_instance, sizeof (vl.type_instance),
240 r_area->instances_buffer, r->instances_num, "-");
241 if (status != 0)
242 {
243 ERROR ("udb_result_submit: creating type_instance failed with status %d.",
244 status);
245 return (status);
246 }
247 }
248 else
249 {
250 char tmp[DATA_MAX_NAME_LEN];
252 int status = strjoin (tmp, sizeof (tmp), r_area->instances_buffer,
253 r->instances_num, "-");
254 if (status != 0)
255 {
256 ERROR ("udb_result_submit: creating type_instance failed with status %d.",
257 status);
258 return (status);
259 }
260 tmp[sizeof (tmp) - 1] = 0;
262 snprintf (vl.type_instance, sizeof (vl.type_instance), "%s-%s",
263 r->instance_prefix, tmp);
264 }
265 }
266 vl.type_instance[sizeof (vl.type_instance) - 1] = 0;
267 /* }}} */
269 plugin_dispatch_values (&vl);
271 sfree (vl.values);
272 return (0);
273 } /* }}} void udb_result_submit */
275 static void udb_result_finish_result (udb_result_t const *r, /* {{{ */
276 udb_result_preparation_area_t *prep_area)
277 {
278 if ((r == NULL) || (prep_area == NULL))
279 return;
281 prep_area->ds = NULL;
282 sfree (prep_area->instances_pos);
283 sfree (prep_area->values_pos);
284 sfree (prep_area->instances_buffer);
285 sfree (prep_area->values_buffer);
286 } /* }}} void udb_result_finish_result */
288 static int udb_result_handle_result (udb_result_t *r, /* {{{ */
289 udb_query_preparation_area_t *q_area,
290 udb_result_preparation_area_t *r_area,
291 udb_query_t const *q, char **column_values)
292 {
293 size_t i;
295 assert (r && q_area && r_area);
297 for (i = 0; i < r->instances_num; i++)
298 r_area->instances_buffer[i] = column_values[r_area->instances_pos[i]];
300 for (i = 0; i < r->values_num; i++)
301 r_area->values_buffer[i] = column_values[r_area->values_pos[i]];
303 return udb_result_submit (r, r_area, q, q_area);
304 } /* }}} int udb_result_handle_result */
306 static int udb_result_prepare_result (udb_result_t const *r, /* {{{ */
307 udb_result_preparation_area_t *prep_area,
308 char **column_names, size_t column_num)
309 {
310 size_t i;
312 if ((r == NULL) || (prep_area == NULL))
313 return (-EINVAL);
315 #define BAIL_OUT(status) \
316 prep_area->ds = NULL; \
317 sfree (prep_area->instances_pos); \
318 sfree (prep_area->values_pos); \
319 sfree (prep_area->instances_buffer); \
320 sfree (prep_area->values_buffer); \
321 return (status)
323 /* Make sure previous preparations are cleaned up. */
324 udb_result_finish_result (r, prep_area);
325 prep_area->instances_pos = NULL;
326 prep_area->values_pos = NULL;
328 /* Read `ds' and check number of values {{{ */
329 prep_area->ds = plugin_get_ds (r->type);
330 if (prep_area->ds == NULL)
331 {
332 ERROR ("db query utils: udb_result_prepare_result: Type `%s' is not "
333 "known by the daemon. See types.db(5) for details.",
334 r->type);
335 BAIL_OUT (-1);
336 }
338 if (((size_t) prep_area->ds->ds_num) != r->values_num)
339 {
340 ERROR ("db query utils: udb_result_prepare_result: The type `%s' "
341 "requires exactly %i value%s, but the configuration specifies %zu.",
342 r->type,
343 prep_area->ds->ds_num, (prep_area->ds->ds_num == 1) ? "" : "s",
344 r->values_num);
345 BAIL_OUT (-1);
346 }
347 /* }}} */
349 /* Allocate r->instances_pos, r->values_pos, r->instances_buffer, and
350 * r->values_buffer {{{ */
351 if (r->instances_num > 0)
352 {
353 prep_area->instances_pos
354 = (size_t *) calloc (r->instances_num, sizeof (size_t));
355 if (prep_area->instances_pos == NULL)
356 {
357 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
358 BAIL_OUT (-ENOMEM);
359 }
361 prep_area->instances_buffer
362 = (char **) calloc (r->instances_num, sizeof (char *));
363 if (prep_area->instances_buffer == NULL)
364 {
365 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
366 BAIL_OUT (-ENOMEM);
367 }
368 } /* if (r->instances_num > 0) */
370 prep_area->values_pos
371 = (size_t *) calloc (r->values_num, sizeof (size_t));
372 if (prep_area->values_pos == NULL)
373 {
374 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
375 BAIL_OUT (-ENOMEM);
376 }
378 prep_area->values_buffer
379 = (char **) calloc (r->values_num, sizeof (char *));
380 if (prep_area->values_buffer == NULL)
381 {
382 ERROR ("db query utils: udb_result_prepare_result: malloc failed.");
383 BAIL_OUT (-ENOMEM);
384 }
385 /* }}} */
387 /* Determine the position of the instance columns {{{ */
388 for (i = 0; i < r->instances_num; i++)
389 {
390 size_t j;
392 for (j = 0; j < column_num; j++)
393 {
394 if (strcasecmp (r->instances[i], column_names[j]) == 0)
395 {
396 prep_area->instances_pos[i] = j;
397 break;
398 }
399 }
401 if (j >= column_num)
402 {
403 ERROR ("db query utils: udb_result_prepare_result: "
404 "Column `%s' could not be found.",
405 r->instances[i]);
406 BAIL_OUT (-ENOENT);
407 }
408 } /* }}} for (i = 0; i < r->instances_num; i++) */
410 /* Determine the position of the value columns {{{ */
411 for (i = 0; i < r->values_num; i++)
412 {
413 size_t j;
415 for (j = 0; j < column_num; j++)
416 {
417 if (strcasecmp (r->values[i], column_names[j]) == 0)
418 {
419 prep_area->values_pos[i] = j;
420 break;
421 }
422 }
424 if (j >= column_num)
425 {
426 ERROR ("db query utils: udb_result_prepare_result: "
427 "Column `%s' could not be found.",
428 r->values[i]);
429 BAIL_OUT (-ENOENT);
430 }
431 } /* }}} for (i = 0; i < r->values_num; i++) */
433 #undef BAIL_OUT
434 return (0);
435 } /* }}} int udb_result_prepare_result */
437 static void udb_result_free (udb_result_t *r) /* {{{ */
438 {
439 size_t i;
441 if (r == NULL)
442 return;
444 sfree (r->type);
446 for (i = 0; i < r->instances_num; i++)
447 sfree (r->instances[i]);
448 sfree (r->instances);
450 for (i = 0; i < r->values_num; i++)
451 sfree (r->values[i]);
452 sfree (r->values);
454 udb_result_free (r->next);
456 sfree (r);
457 } /* }}} void udb_result_free */
459 static int udb_result_create (const char *query_name, /* {{{ */
460 udb_result_t **r_head, oconfig_item_t *ci)
461 {
462 udb_result_t *r;
463 int status;
464 int i;
466 if (ci->values_num != 0)
467 {
468 WARNING ("db query utils: The `Result' block doesn't accept "
469 "any arguments. Ignoring %i argument%s.",
470 ci->values_num, (ci->values_num == 1) ? "" : "s");
471 }
473 r = (udb_result_t *) malloc (sizeof (*r));
474 if (r == NULL)
475 {
476 ERROR ("db query utils: malloc failed.");
477 return (-1);
478 }
479 memset (r, 0, sizeof (*r));
480 r->type = NULL;
481 r->instance_prefix = NULL;
482 r->instances = NULL;
483 r->values = NULL;
484 r->next = NULL;
486 /* Fill the `udb_result_t' structure.. */
487 status = 0;
488 for (i = 0; i < ci->children_num; i++)
489 {
490 oconfig_item_t *child = ci->children + i;
492 if (strcasecmp ("Type", child->key) == 0)
493 status = udb_config_set_string (&r->type, child);
494 else if (strcasecmp ("InstancePrefix", child->key) == 0)
495 status = udb_config_set_string (&r->instance_prefix, child);
496 else if (strcasecmp ("InstancesFrom", child->key) == 0)
497 status = udb_config_add_string (&r->instances, &r->instances_num, child);
498 else if (strcasecmp ("ValuesFrom", child->key) == 0)
499 status = udb_config_add_string (&r->values, &r->values_num, child);
500 else
501 {
502 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
503 query_name, child->key);
504 status = -1;
505 }
507 if (status != 0)
508 break;
509 }
511 /* Check that all necessary options have been given. */
512 while (status == 0)
513 {
514 if (r->type == NULL)
515 {
516 WARNING ("db query utils: `Type' not given for "
517 "result in query `%s'", query_name);
518 status = -1;
519 }
520 if (r->values == NULL)
521 {
522 WARNING ("db query utils: `ValuesFrom' not given for "
523 "result in query `%s'", query_name);
524 status = -1;
525 }
527 break;
528 } /* while (status == 0) */
530 if (status != 0)
531 {
532 udb_result_free (r);
533 return (-1);
534 }
536 /* If all went well, add this result to the list of results. */
537 if (*r_head == NULL)
538 {
539 *r_head = r;
540 }
541 else
542 {
543 udb_result_t *last;
545 last = *r_head;
546 while (last->next != NULL)
547 last = last->next;
549 last->next = r;
550 }
552 return (0);
553 } /* }}} int udb_result_create */
555 /*
556 * Query private functions
557 */
558 static void udb_query_free_one (udb_query_t *q) /* {{{ */
559 {
560 if (q == NULL)
561 return;
563 sfree (q->name);
564 sfree (q->statement);
566 udb_result_free (q->results);
568 sfree (q);
569 } /* }}} void udb_query_free_one */
571 /*
572 * Query public functions
573 */
574 int udb_query_create (udb_query_t ***ret_query_list, /* {{{ */
575 size_t *ret_query_list_len, oconfig_item_t *ci,
576 udb_query_create_callback_t cb)
577 {
578 udb_query_t **query_list;
579 size_t query_list_len;
581 udb_query_t *q;
582 int status;
583 int i;
585 if ((ret_query_list == NULL) || (ret_query_list_len == NULL))
586 return (-EINVAL);
587 query_list = *ret_query_list;
588 query_list_len = *ret_query_list_len;
590 if ((ci->values_num != 1)
591 || (ci->values[0].type != OCONFIG_TYPE_STRING))
592 {
593 WARNING ("db query utils: The `Query' block "
594 "needs exactly one string argument.");
595 return (-1);
596 }
598 q = (udb_query_t *) malloc (sizeof (*q));
599 if (q == NULL)
600 {
601 ERROR ("db query utils: malloc failed.");
602 return (-1);
603 }
604 memset (q, 0, sizeof (*q));
605 q->min_version = 0;
606 q->max_version = UINT_MAX;
608 status = udb_config_set_string (&q->name, ci);
609 if (status != 0)
610 {
611 sfree (q);
612 return (status);
613 }
615 /* Fill the `udb_query_t' structure.. */
616 for (i = 0; i < ci->children_num; i++)
617 {
618 oconfig_item_t *child = ci->children + i;
620 if (strcasecmp ("Statement", child->key) == 0)
621 status = udb_config_set_string (&q->statement, child);
622 else if (strcasecmp ("Result", child->key) == 0)
623 status = udb_result_create (q->name, &q->results, child);
624 else if (strcasecmp ("MinVersion", child->key) == 0)
625 status = udb_config_set_uint (&q->min_version, child);
626 else if (strcasecmp ("MaxVersion", child->key) == 0)
627 status = udb_config_set_uint (&q->max_version, child);
629 /* Call custom callbacks */
630 else if (cb != NULL)
631 {
632 status = (*cb) (q, child);
633 if (status != 0)
634 {
635 WARNING ("db query utils: The configuration callback failed "
636 "to handle `%s'.", child->key);
637 }
638 }
639 else
640 {
641 WARNING ("db query utils: Query `%s': Option `%s' not allowed here.",
642 q->name, child->key);
643 status = -1;
644 }
646 if (status != 0)
647 break;
648 }
650 /* Check that all necessary options have been given. */
651 if (status == 0)
652 {
653 if (q->statement == NULL)
654 {
655 WARNING ("db query utils: Query `%s': No `Statement' given.", q->name);
656 status = -1;
657 }
658 if (q->results == NULL)
659 {
660 WARNING ("db query utils: Query `%s': No (valid) `Result' block given.",
661 q->name);
662 status = -1;
663 }
664 } /* if (status == 0) */
666 /* If all went well, add this query to the list of queries within the
667 * database structure. */
668 if (status == 0)
669 {
670 udb_query_t **temp;
672 temp = (udb_query_t **) realloc (query_list,
673 sizeof (*query_list) * (query_list_len + 1));
674 if (temp == NULL)
675 {
676 ERROR ("db query utils: realloc failed");
677 status = -1;
678 }
679 else
680 {
681 query_list = temp;
682 query_list[query_list_len] = q;
683 query_list_len++;
684 }
685 }
687 if (status != 0)
688 {
689 udb_query_free_one (q);
690 return (-1);
691 }
693 *ret_query_list = query_list;
694 *ret_query_list_len = query_list_len;
696 return (0);
697 } /* }}} int udb_query_create */
699 void udb_query_free (udb_query_t **query_list, size_t query_list_len) /* {{{ */
700 {
701 size_t i;
703 if (query_list == NULL)
704 return;
706 for (i = 0; i < query_list_len; i++)
707 udb_query_free_one (query_list[i]);
709 sfree (query_list);
710 } /* }}} void udb_query_free */
712 int udb_query_pick_from_list_by_name (const char *name, /* {{{ */
713 udb_query_t **src_list, size_t src_list_len,
714 udb_query_t ***dst_list, size_t *dst_list_len)
715 {
716 size_t i;
717 int num_added;
719 if ((name == NULL) || (src_list == NULL) || (dst_list == NULL)
720 || (dst_list_len == NULL))
721 {
722 ERROR ("db query utils: udb_query_pick_from_list_by_name: "
723 "Invalid argument.");
724 return (-EINVAL);
725 }
727 num_added = 0;
728 for (i = 0; i < src_list_len; i++)
729 {
730 udb_query_t **tmp_list;
731 size_t tmp_list_len;
733 if (strcasecmp (name, src_list[i]->name) != 0)
734 continue;
736 tmp_list_len = *dst_list_len;
737 tmp_list = (udb_query_t **) realloc (*dst_list, (tmp_list_len + 1)
738 * sizeof (udb_query_t *));
739 if (tmp_list == NULL)
740 {
741 ERROR ("db query utils: realloc failed.");
742 return (-ENOMEM);
743 }
745 tmp_list[tmp_list_len] = src_list[i];
746 tmp_list_len++;
748 *dst_list = tmp_list;
749 *dst_list_len = tmp_list_len;
751 num_added++;
752 } /* for (i = 0; i < src_list_len; i++) */
754 if (num_added <= 0)
755 {
756 ERROR ("db query utils: Cannot find query `%s'. Make sure the <Query> "
757 "block is above the database definition!",
758 name);
759 return (-ENOENT);
760 }
761 else
762 {
763 DEBUG ("db query utils: Added %i versions of query `%s'.",
764 num_added, name);
765 }
767 return (0);
768 } /* }}} int udb_query_pick_from_list_by_name */
770 int udb_query_pick_from_list (oconfig_item_t *ci, /* {{{ */
771 udb_query_t **src_list, size_t src_list_len,
772 udb_query_t ***dst_list, size_t *dst_list_len)
773 {
774 const char *name;
776 if ((ci == NULL) || (src_list == NULL) || (dst_list == NULL)
777 || (dst_list_len == NULL))
778 {
779 ERROR ("db query utils: udb_query_pick_from_list: "
780 "Invalid argument.");
781 return (-EINVAL);
782 }
784 if ((ci->values_num != 1)
785 || (ci->values[0].type != OCONFIG_TYPE_STRING))
786 {
787 ERROR ("db query utils: The `%s' config option "
788 "needs exactly one string argument.", ci->key);
789 return (-1);
790 }
791 name = ci->values[0].value.string;
793 return (udb_query_pick_from_list_by_name (name,
794 src_list, src_list_len,
795 dst_list, dst_list_len));
796 } /* }}} int udb_query_pick_from_list */
798 const char *udb_query_get_name (udb_query_t *q) /* {{{ */
799 {
800 if (q == NULL)
801 return (NULL);
803 return (q->name);
804 } /* }}} const char *udb_query_get_name */
806 const char *udb_query_get_statement (udb_query_t *q) /* {{{ */
807 {
808 if (q == NULL)
809 return (NULL);
811 return (q->statement);
812 } /* }}} const char *udb_query_get_statement */
814 void udb_query_set_user_data (udb_query_t *q, void *user_data) /* {{{ */
815 {
816 if (q == NULL)
817 return;
819 q->user_data = user_data;
820 } /* }}} void udb_query_set_user_data */
822 void *udb_query_get_user_data (udb_query_t *q) /* {{{ */
823 {
824 if (q == NULL)
825 return (NULL);
827 return (q->user_data);
828 } /* }}} void *udb_query_get_user_data */
830 int udb_query_check_version (udb_query_t *q, unsigned int version) /* {{{ */
831 {
832 if (q == NULL)
833 return (-EINVAL);
835 if ((version < q->min_version) || (version > q->max_version))
836 return (0);
838 return (1);
839 } /* }}} int udb_query_check_version */
841 void udb_query_finish_result (udb_query_t const *q, /* {{{ */
842 udb_query_preparation_area_t *prep_area)
843 {
844 udb_result_preparation_area_t *r_area;
845 udb_result_t *r;
847 if ((q == NULL) || (prep_area == NULL))
848 return;
850 prep_area->column_num = 0;
851 sfree (prep_area->host);
852 sfree (prep_area->plugin);
853 sfree (prep_area->db_name);
855 prep_area->interval = 0;
857 for (r = q->results, r_area = prep_area->result_prep_areas;
858 r != NULL; r = r->next, r_area = r_area->next)
859 {
860 /* this may happen during error conditions of the caller */
861 if (r_area == NULL)
862 break;
863 udb_result_finish_result (r, r_area);
864 }
865 } /* }}} void udb_query_finish_result */
867 int udb_query_handle_result (udb_query_t const *q, /* {{{ */
868 udb_query_preparation_area_t *prep_area, char **column_values)
869 {
870 udb_result_preparation_area_t *r_area;
871 udb_result_t *r;
872 int success;
873 int status;
875 if ((q == NULL) || (prep_area == NULL))
876 return (-EINVAL);
878 if ((prep_area->column_num < 1) || (prep_area->host == NULL)
879 || (prep_area->plugin == NULL) || (prep_area->db_name == NULL))
880 {
881 ERROR ("db query utils: Query `%s': Query is not prepared; "
882 "can't handle result.", q->name);
883 return (-EINVAL);
884 }
886 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG /* {{{ */
887 do
888 {
889 size_t i;
891 for (i = 0; i < prep_area->column_num; i++)
892 {
893 DEBUG ("db query utils: udb_query_handle_result (%s, %s): "
894 "column[%zu] = %s;",
895 prep_area->db_name, q->name, i, column_values[i]);
896 }
897 } while (0);
898 #endif /* }}} */
900 success = 0;
901 for (r = q->results, r_area = prep_area->result_prep_areas;
902 r != NULL; r = r->next, r_area = r_area->next)
903 {
904 status = udb_result_handle_result (r, prep_area, r_area,
905 q, column_values);
906 if (status == 0)
907 success++;
908 }
910 if (success == 0)
911 {
912 ERROR ("db query utils: udb_query_handle_result (%s, %s): "
913 "All results failed.", prep_area->db_name, q->name);
914 return (-1);
915 }
917 return (0);
918 } /* }}} int udb_query_handle_result */
920 int udb_query_prepare_result (udb_query_t const *q, /* {{{ */
921 udb_query_preparation_area_t *prep_area,
922 const char *host, const char *plugin, const char *db_name,
923 char **column_names, size_t column_num, cdtime_t interval)
924 {
925 udb_result_preparation_area_t *r_area;
926 udb_result_t *r;
927 int status;
929 if ((q == NULL) || (prep_area == NULL))
930 return (-EINVAL);
932 udb_query_finish_result (q, prep_area);
934 prep_area->column_num = column_num;
935 prep_area->host = strdup (host);
936 prep_area->plugin = strdup (plugin);
937 prep_area->db_name = strdup (db_name);
939 prep_area->interval = interval;
941 if ((prep_area->host == NULL) || (prep_area->plugin == NULL)
942 || (prep_area->db_name == NULL))
943 {
944 ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name);
945 udb_query_finish_result (q, prep_area);
946 return (-ENOMEM);
947 }
949 #if defined(COLLECT_DEBUG) && COLLECT_DEBUG
950 do
951 {
952 size_t i;
954 for (i = 0; i < column_num; i++)
955 {
956 DEBUG ("db query utils: udb_query_prepare_result: "
957 "query = %s; column[%zu] = %s;",
958 q->name, i, column_names[i]);
959 }
960 } while (0);
961 #endif
963 for (r = q->results, r_area = prep_area->result_prep_areas;
964 r != NULL; r = r->next, r_area = r_area->next)
965 {
966 if (! r_area)
967 {
968 ERROR ("db query utils: Query `%s': Invalid number of result "
969 "preparation areas.", q->name);
970 udb_query_finish_result (q, prep_area);
971 return (-EINVAL);
972 }
974 status = udb_result_prepare_result (r, r_area, column_names, column_num);
975 if (status != 0)
976 {
977 udb_query_finish_result (q, prep_area);
978 return (status);
979 }
980 }
982 return (0);
983 } /* }}} int udb_query_prepare_result */
985 udb_query_preparation_area_t *
986 udb_query_allocate_preparation_area (udb_query_t *q) /* {{{ */
987 {
988 udb_query_preparation_area_t *q_area;
989 udb_result_preparation_area_t **next_r_area;
990 udb_result_t *r;
992 q_area = malloc (sizeof (*q_area));
993 if (q_area == NULL)
994 return NULL;
995 memset (q_area, 0, sizeof (*q_area));
997 next_r_area = &q_area->result_prep_areas;
998 for (r = q->results; r != NULL; r = r->next)
999 {
1000 udb_result_preparation_area_t *r_area;
1002 r_area = malloc (sizeof (*r_area));
1003 if (r_area == NULL)
1004 {
1005 udb_result_preparation_area_t *a = q_area->result_prep_areas;
1007 while (a != NULL)
1008 {
1009 udb_result_preparation_area_t *next = a->next;
1010 sfree (a);
1011 a = next;
1012 }
1014 free (q_area);
1015 return NULL;
1016 }
1018 memset (r_area, 0, sizeof (*r_area));
1020 *next_r_area = r_area;
1021 next_r_area = &r_area->next;
1022 }
1024 return (q_area);
1025 } /* }}} udb_query_preparation_area_t *udb_query_allocate_preparation_area */
1027 void
1028 udb_query_delete_preparation_area (udb_query_preparation_area_t *q_area) /* {{{ */
1029 {
1030 udb_result_preparation_area_t *r_area;
1032 if (q_area == NULL)
1033 return;
1035 r_area = q_area->result_prep_areas;
1036 while (r_area != NULL)
1037 {
1038 udb_result_preparation_area_t *area = r_area;
1040 r_area = r_area->next;
1042 sfree (area->instances_pos);
1043 sfree (area->values_pos);
1044 sfree (area->instances_buffer);
1045 sfree (area->values_buffer);
1046 free (area);
1047 }
1049 sfree (q_area->host);
1050 sfree (q_area->plugin);
1051 sfree (q_area->db_name);
1053 free (q_area);
1054 } /* }}} void udb_query_delete_preparation_area */
1056 /* vim: set sw=2 sts=2 et fdm=marker : */