1 /*****************************************************************************
2 *
3 * Nagios check_dbi plugin
4 *
5 * License: GPL
6 * Copyright (c) 2011 Nagios Plugins Development Team
7 * Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8 *
9 * Description:
10 *
11 * This file contains the check_dbi plugin
12 *
13 * Runs an arbitrary (SQL) command and checks the result.
14 *
15 *
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 *
29 *
30 *****************************************************************************/
32 const char *progname = "check_dbi";
33 const char *copyright = "2011";
34 const char *email = "nagiosplug-devel@lists.sourceforge.net";
36 #include "common.h"
37 #include "utils.h"
39 #include "netutils.h"
41 #include "regex.h"
43 /* required for NAN */
44 #ifndef _ISOC99_SOURCE
45 #define _ISOC99_SOURCE
46 #endif
48 #include <assert.h>
49 #include <math.h>
51 #include <dbi/dbi.h>
53 #include <stdarg.h>
55 typedef enum {
56 METRIC_CONN_TIME,
57 METRIC_QUERY_RESULT,
58 METRIC_QUERY_TIME,
59 } np_dbi_metric_t;
61 typedef enum {
62 TYPE_NUMERIC,
63 TYPE_STRING,
64 } np_dbi_type_t;
66 typedef struct {
67 char *key;
68 char *value;
69 } driver_option_t;
71 char *host = NULL;
72 int verbose = 0;
74 char *warning_range = NULL;
75 char *critical_range = NULL;
76 thresholds *dbi_thresholds = NULL;
78 char *expect = NULL;
80 regex_t expect_re;
81 char *expect_re_str = NULL;
82 int expect_re_cflags = 0;
84 np_dbi_metric_t metric = METRIC_QUERY_RESULT;
85 np_dbi_type_t type = TYPE_NUMERIC;
87 char *np_dbi_driver = NULL;
88 driver_option_t *np_dbi_options = NULL;
89 int np_dbi_options_num = 0;
90 char *np_dbi_database = NULL;
91 char *np_dbi_query = NULL;
93 int process_arguments (int, char **);
94 int validate_arguments (void);
95 void print_usage (void);
96 void print_help (void);
98 double timediff (struct timeval, struct timeval);
100 void np_dbi_print_error (dbi_conn, char *, ...);
102 int do_query (dbi_conn, const char **, double *, double *);
104 int
105 main (int argc, char **argv)
106 {
107 int status = STATE_UNKNOWN;
109 dbi_driver driver;
110 dbi_conn conn;
112 struct timeval start_timeval, end_timeval;
113 double conn_time = 0.0;
114 double query_time = 0.0;
116 const char *query_val_str = NULL;
117 double query_val = 0.0;
119 int i;
121 setlocale (LC_ALL, "");
122 bindtextdomain (PACKAGE, LOCALEDIR);
123 textdomain (PACKAGE);
125 /* Parse extra opts if any */
126 argv = np_extra_opts (&argc, argv, progname);
128 if (process_arguments (argc, argv) == ERROR)
129 usage4 (_("Could not parse arguments"));
131 /* Set signal handling and alarm */
132 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
133 usage4 (_("Cannot catch SIGALRM"));
134 }
135 alarm (timeout_interval);
137 if (verbose > 2)
138 printf ("Initializing DBI\n");
140 if (dbi_initialize (NULL) < 0) {
141 printf ("UNKNOWN - failed to initialize DBI.\n");
142 return STATE_UNKNOWN;
143 }
145 if (verbose)
146 printf ("Opening DBI driver '%s'\n", np_dbi_driver);
148 driver = dbi_driver_open (np_dbi_driver);
149 if (! driver) {
150 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
151 np_dbi_driver);
153 printf ("Known drivers:\n");
154 for (driver = dbi_driver_list (NULL); driver; driver = dbi_driver_list (driver)) {
155 printf (" - %s\n", dbi_driver_get_name (driver));
156 }
157 return STATE_UNKNOWN;
158 }
160 /* make a connection to the database */
161 gettimeofday (&start_timeval, NULL);
163 conn = dbi_conn_open (driver);
164 if (! conn) {
165 printf ("UNKNOWN - failed top open connection object.\n");
166 dbi_conn_close (conn);
167 return STATE_UNKNOWN;
168 }
170 for (i = 0; i < np_dbi_options_num; ++i) {
171 const char *opt;
173 if (verbose > 1)
174 printf ("Setting DBI driver option '%s' to '%s'\n",
175 np_dbi_options[i].key, np_dbi_options[i].value);
177 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value))
178 continue;
179 /* else: status != 0 */
181 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'",
182 np_dbi_options[i].key, np_dbi_options[i].value);
183 printf ("Known driver options:\n");
185 for (opt = dbi_conn_get_option_list (conn, NULL); opt;
186 opt = dbi_conn_get_option_list (conn, opt)) {
187 printf (" - %s\n", opt);
188 }
189 dbi_conn_close (conn);
190 return STATE_UNKNOWN;
191 }
193 if (host) {
194 if (verbose > 1)
195 printf ("Setting DBI driver option 'host' to '%s'\n", host);
196 dbi_conn_set_option (conn, "host", host);
197 }
199 if (verbose) {
200 const char *dbname, *host;
202 dbname = dbi_conn_get_option (conn, "dbname");
203 host = dbi_conn_get_option (conn, "host");
205 if (! dbname)
206 dbname = "<unspecified>";
207 if (! host)
208 host = "<unspecified>";
210 printf ("Connecting to database '%s' at host '%s'\n",
211 dbname, host);
212 }
214 if (dbi_conn_connect (conn) < 0) {
215 np_dbi_print_error (conn, "UNKOWN - failed to connect to database");
216 return STATE_UNKNOWN;
217 }
219 gettimeofday (&end_timeval, NULL);
220 conn_time = timediff (start_timeval, end_timeval);
222 if (verbose)
223 printf("Time elapsed: %f\n", conn_time);
225 if (metric == METRIC_CONN_TIME)
226 status = get_status (conn_time, dbi_thresholds);
228 /* select a database */
229 if (np_dbi_database) {
230 if (verbose > 1)
231 printf ("Selecting database '%s'\n", np_dbi_database);
233 if (dbi_conn_select_db (conn, np_dbi_database)) {
234 np_dbi_print_error (conn, "UNKOWN - failed to select database '%s'",
235 np_dbi_database);
236 return STATE_UNKNOWN;
237 }
238 }
240 if (np_dbi_query) {
241 /* execute query */
242 status = do_query (conn, &query_val_str, &query_val, &query_time);
243 if (status != STATE_OK)
244 /* do_query prints an error message in this case */
245 return status;
247 if (metric == METRIC_QUERY_RESULT) {
248 if (expect) {
249 if ((! query_val_str) || strcmp (query_val_str, expect))
250 status = STATE_CRITICAL;
251 else
252 status = STATE_OK;
253 }
254 else if (expect_re_str) {
255 int err;
257 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
258 if (! err)
259 status = STATE_OK;
260 else if (err == REG_NOMATCH)
261 status = STATE_CRITICAL;
262 else {
263 char errmsg[1024];
264 regerror (err, &expect_re, errmsg, sizeof (errmsg));
265 printf ("ERROR - failed to execute regular expression: %s\n",
266 errmsg);
267 status = STATE_CRITICAL;
268 }
269 }
270 else
271 status = get_status (query_val, dbi_thresholds);
272 }
273 else if (metric == METRIC_QUERY_TIME)
274 status = get_status (query_time, dbi_thresholds);
275 }
277 if (verbose)
278 printf("Closing connection\n");
279 dbi_conn_close (conn);
281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
282 * which should have been reported and handled (abort) before
283 * ... unless we expected a string to be returned */
284 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val))
285 || (type == TYPE_STRING));
287 assert ((type != TYPE_STRING) || (expect || expect_re_str));
289 printf ("%s - connection time: %fs", state_text (status), conn_time);
290 if (np_dbi_query) {
291 if (type == TYPE_STRING) {
292 assert (expect || expect_re_str);
293 printf (", '%s' returned '%s' in %fs", np_dbi_query,
294 query_val_str ? query_val_str : "<nothing>", query_time);
295 if (status != STATE_OK) {
296 if (expect)
297 printf (" (expected '%s')", expect);
298 else if (expect_re_str)
299 printf (" (expected regex /%s/%s)", expect_re_str,
300 ((expect_re_cflags & REG_ICASE) ? "i" : ""));
301 }
302 }
303 else if (isnan (query_val))
304 printf (", '%s' query execution time: %fs", np_dbi_query, query_time);
305 else
306 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time);
307 }
309 printf (" | conntime=%fs;%s;%s;0;", conn_time,
310 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "",
311 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "");
312 if (np_dbi_query) {
313 if (! isnan (query_val)) /* this is also true when -e is used */
314 printf (" query=%f;%s;%s;;", query_val,
315 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "",
316 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
317 printf (" querytime=%fs;%s;%s;0;", query_time,
318 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
319 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
320 }
321 printf ("\n");
322 return status;
323 }
325 /* process command-line arguments */
326 int
327 process_arguments (int argc, char **argv)
328 {
329 int c;
331 int option = 0;
332 static struct option longopts[] = {
333 STD_LONG_OPTS,
335 {"expect", required_argument, 0, 'e'},
336 {"regex", required_argument, 0, 'r'},
337 {"regexi", required_argument, 0, 'R'},
338 {"metric", required_argument, 0, 'm'},
339 {"driver", required_argument, 0, 'd'},
340 {"option", required_argument, 0, 'o'},
341 {"query", required_argument, 0, 'q'},
342 {"database", required_argument, 0, 'D'},
343 {0, 0, 0, 0}
344 };
346 while (1) {
347 c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
348 longopts, &option);
350 if (c == EOF)
351 break;
353 switch (c) {
354 case '?': /* usage */
355 usage5 ();
356 case 'h': /* help */
357 print_help ();
358 exit (STATE_OK);
359 case 'V': /* version */
360 print_revision (progname, NP_VERSION);
361 exit (STATE_OK);
363 case 'c': /* critical range */
364 critical_range = optarg;
365 type = TYPE_NUMERIC;
366 break;
367 case 'w': /* warning range */
368 warning_range = optarg;
369 type = TYPE_NUMERIC;
370 break;
371 case 'e':
372 expect = optarg;
373 type = TYPE_STRING;
374 break;
375 case 'R':
376 expect_re_cflags = REG_ICASE;
377 /* fall through */
378 case 'r':
379 {
380 int err;
382 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
383 expect_re_str = optarg;
384 type = TYPE_STRING;
386 err = regcomp (&expect_re, expect_re_str, expect_re_cflags);
387 if (err) {
388 char errmsg[1024];
389 regerror (err, &expect_re, errmsg, sizeof (errmsg));
390 printf ("ERROR - failed to compile regular expression: %s\n",
391 errmsg);
392 return ERROR;
393 }
394 break;
395 }
397 case 'm':
398 if (! strcasecmp (optarg, "CONN_TIME"))
399 metric = METRIC_CONN_TIME;
400 else if (! strcasecmp (optarg, "QUERY_RESULT"))
401 metric = METRIC_QUERY_RESULT;
402 else if (! strcasecmp (optarg, "QUERY_TIME"))
403 metric = METRIC_QUERY_TIME;
404 else
405 usage2 (_("Invalid metric"), optarg);
406 break;
407 case 't': /* timeout */
408 if (!is_intnonneg (optarg))
409 usage2 (_("Timeout interval must be a positive integer"), optarg);
410 else
411 timeout_interval = atoi (optarg);
413 case 'H': /* host */
414 if (!is_host (optarg))
415 usage2 (_("Invalid hostname/address"), optarg);
416 else
417 host = optarg;
418 break;
419 case 'v':
420 verbose++;
421 break;
423 case 'd':
424 np_dbi_driver = optarg;
425 break;
426 case 'o':
427 {
428 driver_option_t *new;
430 char *k, *v;
432 k = optarg;
433 v = strchr (k, (int)'=');
435 if (! v)
436 usage2 (_("Option must be '<key>=<value>'"), optarg);
438 *v = '\0';
439 ++v;
441 new = realloc (np_dbi_options,
442 (np_dbi_options_num + 1) * sizeof (*new));
443 if (! new) {
444 printf ("UNKOWN - failed to reallocate memory\n");
445 exit (STATE_UNKNOWN);
446 }
448 np_dbi_options = new;
449 new = np_dbi_options + np_dbi_options_num;
450 ++np_dbi_options_num;
452 new->key = k;
453 new->value = v;
454 }
455 break;
456 case 'q':
457 np_dbi_query = optarg;
458 break;
459 case 'D':
460 np_dbi_database = optarg;
461 break;
462 }
463 }
465 set_thresholds (&dbi_thresholds, warning_range, critical_range);
467 return validate_arguments ();
468 }
470 int
471 validate_arguments ()
472 {
473 if (! np_dbi_driver)
474 usage ("Must specify a DBI driver");
476 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME))
477 && (! np_dbi_query))
478 usage ("Must specify a query to execute (metric == QUERY_RESULT)");
480 if ((metric != METRIC_CONN_TIME)
481 && (metric != METRIC_QUERY_RESULT)
482 && (metric != METRIC_QUERY_TIME))
483 usage ("Invalid metric specified");
485 if (expect && (warning_range || critical_range || expect_re_str))
486 usage ("Do not mix -e and -w/-c/-r/-R");
488 if (expect_re_str && (warning_range || critical_range || expect))
489 usage ("Do not mix -r/-R and -w/-c/-e");
491 if (expect && (metric != METRIC_QUERY_RESULT))
492 usage ("Option -e requires metric QUERY_RESULT");
494 if (expect_re_str && (metric != METRIC_QUERY_RESULT))
495 usage ("Options -r/-R require metric QUERY_RESULT");
497 return OK;
498 }
500 void
501 print_help (void)
502 {
503 print_revision (progname, NP_VERSION);
505 printf (COPYRIGHT, copyright, email);
507 printf (_("This program connects to an (SQL) database using DBI and checks the\n"
508 "specified metric against threshold levels. The default metric is\n"
509 "the result of the specified query.\n"));
511 printf ("\n\n");
513 print_usage ();
515 printf (UT_HELP_VRSN);
516 /* include this conditionally to avoid 'zero-length printf format string'
517 * compiler warnings */
518 #ifdef NP_EXTRA_OPTS
519 printf (UT_EXTRA_OPTS);
520 #endif
521 printf ("\n");
523 printf (" %s\n", "-d, --driver=STRING");
524 printf (" %s\n", _("DBI driver to use"));
525 printf (" %s\n", "-o, --option=STRING");
526 printf (" %s\n", _("DBI driver options"));
527 printf (" %s\n", "-q, --query=STRING");
528 printf (" %s\n", _("query to execute"));
529 printf ("\n");
531 printf (UT_WARN_CRIT_RANGE);
532 printf (" %s\n", "-e, --expect=STRING");
533 printf (" %s\n", _("String to expect as query result"));
534 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
535 printf (" %s\n", "-r, --regex=REGEX");
536 printf (" %s\n", _("Extended POSIX regular expression to check query result against"));
537 printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
538 printf (" %s\n", "-R, --regexi=REGEX");
539 printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
540 printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
541 printf (" %s\n", "-m, --metric=METRIC");
542 printf (" %s\n", _("Metric to check thresholds against. Available metrics:"));
543 printf (" CONN_TIME - %s\n", _("time used for setting up the database connection"));
544 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
545 printf (" QUERY_TIME - %s\n", _("time used to execute the query"));
546 printf (" %s\n", _("(ignore the query result)"));
547 printf ("\n");
549 printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
551 printf (UT_VERBOSE);
553 printf ("\n");
554 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
555 printf (" %s\n\n", _("on a query, one has to be specified (-q option)."));
557 printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
558 printf (" %s\n", _("executes the specified query. The first column of the first row of the"));
559 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
560 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
561 printf (" %s\n\n", _("(strings representing numbers are fine)."));
563 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual"));
564 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
565 printf (" %s\n\n", _("for details."));
567 printf (" %s\n", _("Examples:"));
568 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
569 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
570 printf (" Warning if more than five connections; critical if more than ten.\n\n");
572 printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
573 printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
574 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n");
575 printf (" if more than 50 users.\n\n");
577 printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
578 printf (" -m CONN_TIME -w 0.5 -c 2\n");
579 printf (" Warning if connecting to the database takes more than half of a second;\n");
580 printf (" critical if it takes more than 2 seconds.\n");
582 printf (UT_SUPPORT);
583 }
585 void
586 print_usage (void)
587 {
588 printf ("%s\n", _("Usage:"));
589 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
590 printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
591 printf (" [-e <string>] [-r|-R <regex>]\n");
592 }
594 #define CHECK_IGNORE_ERROR(s) \
595 do { \
596 if (metric != METRIC_QUERY_RESULT) \
597 return (s); \
598 } while (0)
600 const char *
601 get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
602 {
603 const char *str;
605 if (field_type != DBI_TYPE_STRING) {
606 printf ("CRITICAL - result value is not a string\n");
607 return NULL;
608 }
610 str = dbi_result_get_string_idx (res, 1);
611 if ((! str) || (strcmp (str, "ERROR") == 0)) {
612 CHECK_IGNORE_ERROR (NULL);
613 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value");
614 return NULL;
615 }
617 if ((verbose && (type == TYPE_STRING)) || (verbose > 2))
618 printf ("Query returned string '%s'\n", str);
619 return str;
620 }
622 double
623 get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
624 {
625 double val = NAN;
627 if (*field_type == DBI_TYPE_INTEGER) {
628 val = (double)dbi_result_get_longlong_idx (res, 1);
629 }
630 else if (*field_type == DBI_TYPE_DECIMAL) {
631 val = dbi_result_get_double_idx (res, 1);
632 }
633 else if (*field_type == DBI_TYPE_STRING) {
634 const char *val_str;
635 char *endptr = NULL;
637 val_str = get_field_str (conn, res, *field_type);
638 if (! val_str) {
639 CHECK_IGNORE_ERROR (NAN);
640 *field_type = DBI_TYPE_ERROR;
641 return NAN;
642 }
644 val = strtod (val_str, &endptr);
645 if (endptr == val_str) {
646 CHECK_IGNORE_ERROR (NAN);
647 printf ("CRITICAL - result value is not a numeric: %s\n", val_str);
648 *field_type = DBI_TYPE_ERROR;
649 return NAN;
650 }
651 else if ((endptr != NULL) && (*endptr != '\0')) {
652 if (verbose)
653 printf ("Garbage after value: %s\n", endptr);
654 }
655 }
656 else {
657 CHECK_IGNORE_ERROR (NAN);
658 printf ("CRITICAL - cannot parse value of type %s (%i)\n",
659 (*field_type == DBI_TYPE_BINARY)
660 ? "BINARY"
661 : (*field_type == DBI_TYPE_DATETIME)
662 ? "DATETIME"
663 : "<unknown>",
664 *field_type);
665 *field_type = DBI_TYPE_ERROR;
666 return NAN;
667 }
668 return val;
669 }
671 double
672 get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
673 {
674 unsigned short field_type;
675 double val = NAN;
677 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) {
678 CHECK_IGNORE_ERROR (STATE_OK);
679 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows");
680 return STATE_CRITICAL;
681 }
683 if (dbi_result_get_numrows (res) < 1) {
684 CHECK_IGNORE_ERROR (STATE_OK);
685 printf ("WARNING - no rows returned\n");
686 return STATE_WARNING;
687 }
689 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) {
690 CHECK_IGNORE_ERROR (STATE_OK);
691 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields");
692 return STATE_CRITICAL;
693 }
695 if (dbi_result_get_numfields (res) < 1) {
696 CHECK_IGNORE_ERROR (STATE_OK);
697 printf ("WARNING - no fields returned\n");
698 return STATE_WARNING;
699 }
701 if (dbi_result_first_row (res) != 1) {
702 CHECK_IGNORE_ERROR (STATE_OK);
703 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row");
704 return STATE_CRITICAL;
705 }
707 field_type = dbi_result_get_field_type_idx (res, 1);
708 if (field_type != DBI_TYPE_ERROR) {
709 if (type == TYPE_STRING)
710 /* the value will be freed in dbi_result_free */
711 *res_val_str = strdup (get_field_str (conn, res, field_type));
712 else
713 val = get_field (conn, res, &field_type);
714 }
716 *res_val = val;
718 if (field_type == DBI_TYPE_ERROR) {
719 CHECK_IGNORE_ERROR (STATE_OK);
720 np_dbi_print_error (conn, "CRITICAL - failed to fetch data");
721 return STATE_CRITICAL;
722 }
724 dbi_result_free (res);
725 return STATE_OK;
726 }
728 #undef CHECK_IGNORE_ERROR
730 int
731 do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
732 {
733 dbi_result res;
735 struct timeval timeval_start, timeval_end;
736 int status = STATE_OK;
738 assert (np_dbi_query);
740 if (verbose)
741 printf ("Executing query '%s'\n", np_dbi_query);
743 gettimeofday (&timeval_start, NULL);
745 res = dbi_conn_query (conn, np_dbi_query);
746 if (! res) {
747 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
748 return STATE_CRITICAL;
749 }
751 status = get_query_result (conn, res, res_val_str, res_val);
753 gettimeofday (&timeval_end, NULL);
754 *res_time = timediff (timeval_start, timeval_end);
756 if (verbose)
757 printf ("Time elapsed: %f\n", *res_time);
759 return status;
760 }
762 double
763 timediff (struct timeval start, struct timeval end)
764 {
765 double diff;
767 while (start.tv_usec > end.tv_usec) {
768 --end.tv_sec;
769 end.tv_usec += 1000000;
770 }
771 diff = (double)(end.tv_sec - start.tv_sec)
772 + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
773 return diff;
774 }
776 void
777 np_dbi_print_error (dbi_conn conn, char *fmt, ...)
778 {
779 const char *errmsg = NULL;
780 va_list ap;
782 va_start (ap, fmt);
784 dbi_conn_error (conn, &errmsg);
785 vprintf (fmt, ap);
786 printf (": %s\n", errmsg);
788 va_end (ap);
789 }