Code

check_dbi: Added simple regex example to help output.
[nagiosplug.git] / plugins / check_dbi.c
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_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 *);
105 int
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"));
137         }
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.\n");
145                 return STATE_UNKNOWN;
146         }
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));
159                 }
160                 return STATE_UNKNOWN;
161         }
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;
171         }
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);
191                 }
192                 dbi_conn_close (conn);
193                 return STATE_UNKNOWN;
194         }
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);
200         }
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);
215         }
217         if (dbi_conn_connect (conn) < 0) {
218                 np_dbi_print_error (conn, "UNKOWN - failed to connect to database");
219                 return STATE_UNKNOWN;
220         }
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, "UNKOWN - failed to select database '%s'",
245                                         np_dbi_database);
246                         return STATE_UNKNOWN;
247                 }
248         }
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;
263                         }
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;
278                                 }
279                         }
280                         else
281                                 status = get_status (query_val, dbi_thresholds);
282                 }
283                 else if (metric == METRIC_QUERY_TIME)
284                         status = get_status (query_time, dbi_thresholds);
285         }
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" : ""));
311                         }
312                 }
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);
317         }
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 : "");
333         }
334         printf ("\n");
335         return status;
338 /* process command-line arguments */
339 int
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}
357         };
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_OK);
372                 case 'V':     /* version */
373                         print_revision (progname, NP_VERSION);
374                         exit (STATE_OK);
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':
392                         {
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;
406                                 }
407                                 break;
408                         }
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':
442                         {
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 ("UNKOWN - failed to reallocate memory\n");
460                                         exit (STATE_UNKNOWN);
461                                 }
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;
469                         }
470                         break;
471                 case 'q':
472                         np_dbi_query = optarg;
473                         break;
474                 case 'D':
475                         np_dbi_database = optarg;
476                         break;
477                 }
478         }
480         set_thresholds (&dbi_thresholds, warning_range, critical_range);
482         return validate_arguments ();
485 int
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_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;
635         }
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;
642         }
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);
656         }
657         else if (*field_type == DBI_TYPE_DECIMAL) {
658                 val = dbi_result_get_double_idx (res, 1);
659         }
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;
669                 }
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;
677                 }
678                 else if ((endptr != NULL) && (*endptr != '\0')) {
679                         if (verbose)
680                                 printf ("Garbage after value: %s\n", endptr);
681                 }
682         }
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;
694         }
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;
708         }
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;
714         }
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;
720         }
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;
726         }
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;
732         }
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);
741         }
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;
749         }
751         dbi_result_free (res);
752         return STATE_OK;
755 #undef CHECK_IGNORE_ERROR
757 int
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;
776         }
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;
797         }
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);