Merge remote-tracking branch 'upstream/pr/1456'
[monitoring-plugins.git] / plugins / check_dbi.c
blob826eb8d91a41f31b246d66215d0824bad0ea2d93
1 /*****************************************************************************
2 *
3 * Monitoring check_dbi plugin
4 *
5 * License: GPL
6 * Copyright (c) 2011 Monitoring Plugins Development Team
7 * Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8 *
9 * Description:
11 * This file contains the check_dbi plugin
13 * Runs an arbitrary (SQL) command and checks the result.
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.
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.
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/>.
30 *****************************************************************************/
32 const char *progname = "check_dbi";
33 const char *copyright = "2011";
34 const char *email = "devel@monitoring-plugins.org";
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_SERVER_VERSION,
58 METRIC_QUERY_RESULT,
59 METRIC_QUERY_TIME,
60 } np_dbi_metric_t;
62 typedef enum {
63 TYPE_NUMERIC,
64 TYPE_STRING,
65 } np_dbi_type_t;
67 typedef struct {
68 char *key;
69 char *value;
70 } driver_option_t;
72 char *host = NULL;
73 int verbose = 0;
75 char *warning_range = NULL;
76 char *critical_range = NULL;
77 thresholds *dbi_thresholds = NULL;
79 char *expect = NULL;
81 regex_t expect_re;
82 char *expect_re_str = NULL;
83 int expect_re_cflags = 0;
85 np_dbi_metric_t metric = METRIC_QUERY_RESULT;
86 np_dbi_type_t type = TYPE_NUMERIC;
88 char *np_dbi_driver = NULL;
89 driver_option_t *np_dbi_options = NULL;
90 int np_dbi_options_num = 0;
91 char *np_dbi_database = NULL;
92 char *np_dbi_query = NULL;
94 int process_arguments (int, char **);
95 int validate_arguments (void);
96 void print_usage (void);
97 void print_help (void);
99 double timediff (struct timeval, struct timeval);
101 void np_dbi_print_error (dbi_conn, char *, ...);
103 int do_query (dbi_conn, const char **, double *, double *);
106 main (int argc, char **argv)
108 int status = STATE_UNKNOWN;
110 dbi_driver driver;
111 dbi_conn conn;
113 unsigned int server_version;
115 struct timeval start_timeval, end_timeval;
116 double conn_time = 0.0;
117 double query_time = 0.0;
119 const char *query_val_str = NULL;
120 double query_val = 0.0;
122 int i;
124 setlocale (LC_ALL, "");
125 bindtextdomain (PACKAGE, LOCALEDIR);
126 textdomain (PACKAGE);
128 /* Parse extra opts if any */
129 argv = np_extra_opts (&argc, argv, progname);
131 if (process_arguments (argc, argv) == ERROR)
132 usage4 (_("Could not parse arguments"));
134 /* Set signal handling and alarm */
135 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
136 usage4 (_("Cannot catch SIGALRM"));
138 alarm (timeout_interval);
140 if (verbose > 2)
141 printf ("Initializing DBI\n");
143 if (dbi_initialize (NULL) < 0) {
144 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
145 return STATE_UNKNOWN;
148 if (verbose)
149 printf ("Opening DBI driver '%s'\n", np_dbi_driver);
151 driver = dbi_driver_open (np_dbi_driver);
152 if (! driver) {
153 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
154 np_dbi_driver);
156 printf ("Known drivers:\n");
157 for (driver = dbi_driver_list (NULL); driver; driver = dbi_driver_list (driver)) {
158 printf (" - %s\n", dbi_driver_get_name (driver));
160 return STATE_UNKNOWN;
163 /* make a connection to the database */
164 gettimeofday (&start_timeval, NULL);
166 conn = dbi_conn_open (driver);
167 if (! conn) {
168 printf ("UNKNOWN - failed top open connection object.\n");
169 dbi_conn_close (conn);
170 return STATE_UNKNOWN;
173 for (i = 0; i < np_dbi_options_num; ++i) {
174 const char *opt;
176 if (verbose > 1)
177 printf ("Setting DBI driver option '%s' to '%s'\n",
178 np_dbi_options[i].key, np_dbi_options[i].value);
180 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value))
181 continue;
182 /* else: status != 0 */
184 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'",
185 np_dbi_options[i].key, np_dbi_options[i].value);
186 printf ("Known driver options:\n");
188 for (opt = dbi_conn_get_option_list (conn, NULL); opt;
189 opt = dbi_conn_get_option_list (conn, opt)) {
190 printf (" - %s\n", opt);
192 dbi_conn_close (conn);
193 return STATE_UNKNOWN;
196 if (host) {
197 if (verbose > 1)
198 printf ("Setting DBI driver option 'host' to '%s'\n", host);
199 dbi_conn_set_option (conn, "host", host);
202 if (verbose) {
203 const char *dbname, *host;
205 dbname = dbi_conn_get_option (conn, "dbname");
206 host = dbi_conn_get_option (conn, "host");
208 if (! dbname)
209 dbname = "<unspecified>";
210 if (! host)
211 host = "<unspecified>";
213 printf ("Connecting to database '%s' at host '%s'\n",
214 dbname, host);
217 if (dbi_conn_connect (conn) < 0) {
218 np_dbi_print_error (conn, "UNKNOWN - failed to connect to database");
219 return STATE_UNKNOWN;
222 gettimeofday (&end_timeval, NULL);
223 conn_time = timediff (start_timeval, end_timeval);
225 server_version = dbi_conn_get_engine_version (conn);
226 if (verbose)
227 printf ("Connected to server version %u\n", server_version);
229 if (metric == METRIC_SERVER_VERSION)
230 status = get_status (server_version, dbi_thresholds);
232 if (verbose)
233 printf ("Time elapsed: %f\n", conn_time);
235 if (metric == METRIC_CONN_TIME)
236 status = get_status (conn_time, dbi_thresholds);
238 /* select a database */
239 if (np_dbi_database) {
240 if (verbose > 1)
241 printf ("Selecting database '%s'\n", np_dbi_database);
243 if (dbi_conn_select_db (conn, np_dbi_database)) {
244 np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'",
245 np_dbi_database);
246 return STATE_UNKNOWN;
250 if (np_dbi_query) {
251 /* execute query */
252 status = do_query (conn, &query_val_str, &query_val, &query_time);
253 if (status != STATE_OK)
254 /* do_query prints an error message in this case */
255 return status;
257 if (metric == METRIC_QUERY_RESULT) {
258 if (expect) {
259 if ((! query_val_str) || strcmp (query_val_str, expect))
260 status = STATE_CRITICAL;
261 else
262 status = STATE_OK;
264 else if (expect_re_str) {
265 int err;
267 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
268 if (! err)
269 status = STATE_OK;
270 else if (err == REG_NOMATCH)
271 status = STATE_CRITICAL;
272 else {
273 char errmsg[1024];
274 regerror (err, &expect_re, errmsg, sizeof (errmsg));
275 printf ("ERROR - failed to execute regular expression: %s\n",
276 errmsg);
277 status = STATE_CRITICAL;
280 else
281 status = get_status (query_val, dbi_thresholds);
283 else if (metric == METRIC_QUERY_TIME)
284 status = get_status (query_time, dbi_thresholds);
287 if (verbose)
288 printf("Closing connection\n");
289 dbi_conn_close (conn);
291 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
292 * which should have been reported and handled (abort) before
293 * ... unless we expected a string to be returned */
294 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val))
295 || (type == TYPE_STRING));
297 assert ((type != TYPE_STRING) || (expect || expect_re_str));
299 printf ("%s - connection time: %fs", state_text (status), conn_time);
300 if (np_dbi_query) {
301 if (type == TYPE_STRING) {
302 assert (expect || expect_re_str);
303 printf (", '%s' returned '%s' in %fs", np_dbi_query,
304 query_val_str ? query_val_str : "<nothing>", query_time);
305 if (status != STATE_OK) {
306 if (expect)
307 printf (" (expected '%s')", expect);
308 else if (expect_re_str)
309 printf (" (expected regex /%s/%s)", expect_re_str,
310 ((expect_re_cflags & REG_ICASE) ? "i" : ""));
313 else if (isnan (query_val))
314 printf (", '%s' query execution time: %fs", np_dbi_query, query_time);
315 else
316 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time);
319 printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
320 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "",
321 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "",
322 server_version,
323 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "",
324 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : "");
325 if (np_dbi_query) {
326 if (! isnan (query_val)) /* this is also true when -e is used */
327 printf (" query=%f;%s;%s;;", query_val,
328 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "",
329 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
330 printf (" querytime=%fs;%s;%s;0;", query_time,
331 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
332 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
334 printf ("\n");
335 return status;
338 /* process command-line arguments */
340 process_arguments (int argc, char **argv)
342 int c;
344 int option = 0;
345 static struct option longopts[] = {
346 STD_LONG_OPTS,
348 {"expect", required_argument, 0, 'e'},
349 {"regex", required_argument, 0, 'r'},
350 {"regexi", required_argument, 0, 'R'},
351 {"metric", required_argument, 0, 'm'},
352 {"driver", required_argument, 0, 'd'},
353 {"option", required_argument, 0, 'o'},
354 {"query", required_argument, 0, 'q'},
355 {"database", required_argument, 0, 'D'},
356 {0, 0, 0, 0}
359 while (1) {
360 c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
361 longopts, &option);
363 if (c == EOF)
364 break;
366 switch (c) {
367 case '?': /* usage */
368 usage5 ();
369 case 'h': /* help */
370 print_help ();
371 exit (STATE_UNKNOWN);
372 case 'V': /* version */
373 print_revision (progname, NP_VERSION);
374 exit (STATE_UNKNOWN);
376 case 'c': /* critical range */
377 critical_range = optarg;
378 type = TYPE_NUMERIC;
379 break;
380 case 'w': /* warning range */
381 warning_range = optarg;
382 type = TYPE_NUMERIC;
383 break;
384 case 'e':
385 expect = optarg;
386 type = TYPE_STRING;
387 break;
388 case 'R':
389 expect_re_cflags = REG_ICASE;
390 /* fall through */
391 case 'r':
393 int err;
395 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
396 expect_re_str = optarg;
397 type = TYPE_STRING;
399 err = regcomp (&expect_re, expect_re_str, expect_re_cflags);
400 if (err) {
401 char errmsg[1024];
402 regerror (err, &expect_re, errmsg, sizeof (errmsg));
403 printf ("ERROR - failed to compile regular expression: %s\n",
404 errmsg);
405 return ERROR;
407 break;
410 case 'm':
411 if (! strcasecmp (optarg, "CONN_TIME"))
412 metric = METRIC_CONN_TIME;
413 else if (! strcasecmp (optarg, "SERVER_VERSION"))
414 metric = METRIC_SERVER_VERSION;
415 else if (! strcasecmp (optarg, "QUERY_RESULT"))
416 metric = METRIC_QUERY_RESULT;
417 else if (! strcasecmp (optarg, "QUERY_TIME"))
418 metric = METRIC_QUERY_TIME;
419 else
420 usage2 (_("Invalid metric"), optarg);
421 break;
422 case 't': /* timeout */
423 if (!is_intnonneg (optarg))
424 usage2 (_("Timeout interval must be a positive integer"), optarg);
425 else
426 timeout_interval = atoi (optarg);
428 case 'H': /* host */
429 if (!is_host (optarg))
430 usage2 (_("Invalid hostname/address"), optarg);
431 else
432 host = optarg;
433 break;
434 case 'v':
435 verbose++;
436 break;
438 case 'd':
439 np_dbi_driver = optarg;
440 break;
441 case 'o':
443 driver_option_t *new;
445 char *k, *v;
447 k = optarg;
448 v = strchr (k, (int)'=');
450 if (! v)
451 usage2 (_("Option must be '<key>=<value>'"), optarg);
453 *v = '\0';
454 ++v;
456 new = realloc (np_dbi_options,
457 (np_dbi_options_num + 1) * sizeof (*new));
458 if (! new) {
459 printf ("UNKNOWN - failed to reallocate memory\n");
460 exit (STATE_UNKNOWN);
463 np_dbi_options = new;
464 new = np_dbi_options + np_dbi_options_num;
465 ++np_dbi_options_num;
467 new->key = k;
468 new->value = v;
470 break;
471 case 'q':
472 np_dbi_query = optarg;
473 break;
474 case 'D':
475 np_dbi_database = optarg;
476 break;
480 set_thresholds (&dbi_thresholds, warning_range, critical_range);
482 return validate_arguments ();
486 validate_arguments ()
488 if (! np_dbi_driver)
489 usage ("Must specify a DBI driver");
491 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME))
492 && (! np_dbi_query))
493 usage ("Must specify a query to execute (metric == QUERY_RESULT)");
495 if ((metric != METRIC_CONN_TIME)
496 && (metric != METRIC_SERVER_VERSION)
497 && (metric != METRIC_QUERY_RESULT)
498 && (metric != METRIC_QUERY_TIME))
499 usage ("Invalid metric specified");
501 if (expect && (warning_range || critical_range || expect_re_str))
502 usage ("Do not mix -e and -w/-c/-r/-R");
504 if (expect_re_str && (warning_range || critical_range || expect))
505 usage ("Do not mix -r/-R and -w/-c/-e");
507 if (expect && (metric != METRIC_QUERY_RESULT))
508 usage ("Option -e requires metric QUERY_RESULT");
510 if (expect_re_str && (metric != METRIC_QUERY_RESULT))
511 usage ("Options -r/-R require metric QUERY_RESULT");
513 return OK;
516 void
517 print_help (void)
519 print_revision (progname, NP_VERSION);
521 printf (COPYRIGHT, copyright, email);
523 printf (_("This program connects to an (SQL) database using DBI and checks the\n"
524 "specified metric against threshold levels. The default metric is\n"
525 "the result of the specified query.\n"));
527 printf ("\n\n");
529 print_usage ();
531 printf (UT_HELP_VRSN);
532 /* include this conditionally to avoid 'zero-length printf format string'
533 * compiler warnings */
534 #ifdef NP_EXTRA_OPTS
535 printf (UT_EXTRA_OPTS);
536 #endif
537 printf ("\n");
539 printf (" %s\n", "-d, --driver=STRING");
540 printf (" %s\n", _("DBI driver to use"));
541 printf (" %s\n", "-o, --option=STRING");
542 printf (" %s\n", _("DBI driver options"));
543 printf (" %s\n", "-q, --query=STRING");
544 printf (" %s\n", _("query to execute"));
545 printf ("\n");
547 printf (UT_WARN_CRIT_RANGE);
548 printf (" %s\n", "-e, --expect=STRING");
549 printf (" %s\n", _("String to expect as query result"));
550 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
551 printf (" %s\n", "-r, --regex=REGEX");
552 printf (" %s\n", _("Extended POSIX regular expression to check query result against"));
553 printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
554 printf (" %s\n", "-R, --regexi=REGEX");
555 printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
556 printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
557 printf (" %s\n", "-m, --metric=METRIC");
558 printf (" %s\n", _("Metric to check thresholds against. Available metrics:"));
559 printf (" CONN_TIME - %s\n", _("time used for setting up the database connection"));
560 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
561 printf (" QUERY_TIME - %s\n", _("time used to execute the query"));
562 printf (" %s\n", _("(ignore the query result)"));
563 printf ("\n");
565 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
567 printf (UT_VERBOSE);
569 printf ("\n");
570 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
571 printf (" %s\n\n", _("on a query, one has to be specified (-q option)."));
573 printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
574 printf (" %s\n", _("executes the specified query. The first column of the first row of the"));
575 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
576 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
577 printf (" %s\n\n", _("(strings representing numbers are fine)."));
579 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual"));
580 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
581 printf (" %s\n\n", _("for details."));
583 printf (" %s\n", _("Examples:"));
584 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
585 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
586 printf (" Warning if more than five connections; critical if more than ten.\n\n");
588 printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
589 printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
590 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n");
591 printf (" if more than 50 users.\n\n");
593 printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
594 printf (" -m CONN_TIME -w 0.5 -c 2\n");
595 printf (" Warning if connecting to the database takes more than half of a second;\n");
596 printf (" critical if it takes more than 2 seconds.\n\n");
598 printf (" check_dbi -d mysql -H localhost -o username=user \\\n");
599 printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
600 printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n");
601 printf (" Critical if the database server is not a MySQL enterprise server in either\n");
602 printf (" version 5.0.x or 5.1.x.\n\n");
604 printf (" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n");
605 printf (" -w 090000:090099 -c 090000:090199\n");
606 printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
607 printf (" is less than 9.x or higher than 9.1.x.\n");
609 printf (UT_SUPPORT);
612 void
613 print_usage (void)
615 printf ("%s\n", _("Usage:"));
616 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
617 printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
618 printf (" [-e <string>] [-r|-R <regex>]\n");
621 #define CHECK_IGNORE_ERROR(s) \
622 do { \
623 if (metric != METRIC_QUERY_RESULT) \
624 return (s); \
625 } while (0)
627 const char *
628 get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
630 const char *str;
632 if (field_type != DBI_TYPE_STRING) {
633 printf ("CRITICAL - result value is not a string\n");
634 return NULL;
637 str = dbi_result_get_string_idx (res, 1);
638 if ((! str) || (strcmp (str, "ERROR") == 0)) {
639 CHECK_IGNORE_ERROR (NULL);
640 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value");
641 return NULL;
644 if ((verbose && (type == TYPE_STRING)) || (verbose > 2))
645 printf ("Query returned string '%s'\n", str);
646 return str;
649 double
650 get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
652 double val = NAN;
654 if (*field_type == DBI_TYPE_INTEGER) {
655 val = (double)dbi_result_get_longlong_idx (res, 1);
657 else if (*field_type == DBI_TYPE_DECIMAL) {
658 val = dbi_result_get_double_idx (res, 1);
660 else if (*field_type == DBI_TYPE_STRING) {
661 const char *val_str;
662 char *endptr = NULL;
664 val_str = get_field_str (conn, res, *field_type);
665 if (! val_str) {
666 CHECK_IGNORE_ERROR (NAN);
667 *field_type = DBI_TYPE_ERROR;
668 return NAN;
671 val = strtod (val_str, &endptr);
672 if (endptr == val_str) {
673 CHECK_IGNORE_ERROR (NAN);
674 printf ("CRITICAL - result value is not a numeric: %s\n", val_str);
675 *field_type = DBI_TYPE_ERROR;
676 return NAN;
678 else if ((endptr != NULL) && (*endptr != '\0')) {
679 if (verbose)
680 printf ("Garbage after value: %s\n", endptr);
683 else {
684 CHECK_IGNORE_ERROR (NAN);
685 printf ("CRITICAL - cannot parse value of type %s (%i)\n",
686 (*field_type == DBI_TYPE_BINARY)
687 ? "BINARY"
688 : (*field_type == DBI_TYPE_DATETIME)
689 ? "DATETIME"
690 : "<unknown>",
691 *field_type);
692 *field_type = DBI_TYPE_ERROR;
693 return NAN;
695 return val;
698 double
699 get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
701 unsigned short field_type;
702 double val = NAN;
704 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) {
705 CHECK_IGNORE_ERROR (STATE_OK);
706 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows");
707 return STATE_CRITICAL;
710 if (dbi_result_get_numrows (res) < 1) {
711 CHECK_IGNORE_ERROR (STATE_OK);
712 printf ("WARNING - no rows returned\n");
713 return STATE_WARNING;
716 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) {
717 CHECK_IGNORE_ERROR (STATE_OK);
718 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields");
719 return STATE_CRITICAL;
722 if (dbi_result_get_numfields (res) < 1) {
723 CHECK_IGNORE_ERROR (STATE_OK);
724 printf ("WARNING - no fields returned\n");
725 return STATE_WARNING;
728 if (dbi_result_first_row (res) != 1) {
729 CHECK_IGNORE_ERROR (STATE_OK);
730 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row");
731 return STATE_CRITICAL;
734 field_type = dbi_result_get_field_type_idx (res, 1);
735 if (field_type != DBI_TYPE_ERROR) {
736 if (type == TYPE_STRING)
737 /* the value will be freed in dbi_result_free */
738 *res_val_str = strdup (get_field_str (conn, res, field_type));
739 else
740 val = get_field (conn, res, &field_type);
743 *res_val = val;
745 if (field_type == DBI_TYPE_ERROR) {
746 CHECK_IGNORE_ERROR (STATE_OK);
747 np_dbi_print_error (conn, "CRITICAL - failed to fetch data");
748 return STATE_CRITICAL;
751 dbi_result_free (res);
752 return STATE_OK;
755 #undef CHECK_IGNORE_ERROR
758 do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
760 dbi_result res;
762 struct timeval timeval_start, timeval_end;
763 int status = STATE_OK;
765 assert (np_dbi_query);
767 if (verbose)
768 printf ("Executing query '%s'\n", np_dbi_query);
770 gettimeofday (&timeval_start, NULL);
772 res = dbi_conn_query (conn, np_dbi_query);
773 if (! res) {
774 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
775 return STATE_CRITICAL;
778 status = get_query_result (conn, res, res_val_str, res_val);
780 gettimeofday (&timeval_end, NULL);
781 *res_time = timediff (timeval_start, timeval_end);
783 if (verbose)
784 printf ("Time elapsed: %f\n", *res_time);
786 return status;
789 double
790 timediff (struct timeval start, struct timeval end)
792 double diff;
794 while (start.tv_usec > end.tv_usec) {
795 --end.tv_sec;
796 end.tv_usec += 1000000;
798 diff = (double)(end.tv_sec - start.tv_sec)
799 + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
800 return diff;
803 void
804 np_dbi_print_error (dbi_conn conn, char *fmt, ...)
806 const char *errmsg = NULL;
807 va_list ap;
809 va_start (ap, fmt);
811 dbi_conn_error (conn, &errmsg);
812 vprintf (fmt, ap);
813 printf (": %s\n", errmsg);
815 va_end (ap);