Code

check_dbi: Added -r and -R options.
[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_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)
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;
325 /* process command-line arguments */
326 int
327 process_arguments (int argc, char **argv)
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 ();
470 int
471 validate_arguments ()
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;
500 void
501 print_help (void)
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);
585 void
586 print_usage (void)
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");
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)
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;
622 double
623 get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
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;
671 double
672 get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
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;
728 #undef CHECK_IGNORE_ERROR
730 int
731 do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
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;
762 double
763 timediff (struct timeval start, struct timeval end)
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;
776 void
777 np_dbi_print_error (dbi_conn conn, char *fmt, ...)
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);