[monitoring-plugins] check_dbi: new output functionality
Lorenz Kästle
git at monitoring-plugins.org
Fri Nov 7 14:20:12 CET 2025
Module: monitoring-plugins
Branch: master
Commit: ec5fd11c1d1f6117e1bccf4955fa99ba5706c6b4
Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
Date: Wed Oct 29 13:05:55 2025 +0100
URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=ec5fd11c
check_dbi: new output functionality
---
plugins/check_dbi.c | 430 ++++++++++++++++++++++++++++++++++----------------
plugins/t/check_dbi.t | 10 +-
2 files changed, 295 insertions(+), 145 deletions(-)
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 786fc1b6..84e3cb5b 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -29,12 +29,14 @@
*
*****************************************************************************/
-#include "states.h"
const char *progname = "check_dbi";
const char *copyright = "2011-2024";
const char *email = "devel at monitoring-plugins.org";
#include "../lib/monitoringplug.h"
+#include "perfdata.h"
+#include "output.h"
+#include "states.h"
#include "check_dbi.d/config.h"
#include "common.h"
#include "utils.h"
@@ -72,9 +74,15 @@ static double timediff(struct timeval /*start*/, struct timeval /*end*/);
static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
-static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/,
- double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
- mp_dbi_type /*type*/, char * /*np_dbi_query*/);
+typedef struct {
+ char *result_string;
+ double result_number;
+ double query_duration;
+ int error_code;
+ const char *error_string;
+ mp_state_enum query_processing_status;
+} do_query_result;
+static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type, char *query);
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
@@ -104,16 +112,17 @@ int main(int argc, char **argv) {
dbi_inst instance_p = NULL;
if (dbi_initialize_r(NULL, &instance_p) < 0) {
- printf(
- "UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
- return STATE_UNKNOWN;
+ printf("failed to initialize DBI; possibly you don't have any drivers installed.\n");
+ exit(STATE_UNKNOWN);
}
+ // Try to prevent libdbi from printing stuff on stderr
+ // Who thought that would be a good idea anyway?
dbi_set_verbosity_r(0, instance_p);
if (instance_p == NULL) {
- printf("UNKNOWN - failed to initialize DBI.\n");
- return STATE_UNKNOWN;
+ printf("failed to initialize DBI.\n");
+ exit(STATE_UNKNOWN);
}
if (verbose) {
@@ -122,15 +131,14 @@ int main(int argc, char **argv) {
dbi_driver driver = dbi_driver_open_r(config.dbi_driver, instance_p);
if (!driver) {
- printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n",
- config.dbi_driver);
+ printf("failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
printf("Known drivers:\n");
for (driver = dbi_driver_list_r(NULL, instance_p); driver;
driver = dbi_driver_list_r(driver, instance_p)) {
printf(" - %s\n", dbi_driver_get_name(driver));
}
- return STATE_UNKNOWN;
+ exit(STATE_UNKNOWN);
}
/* make a connection to the database */
@@ -141,7 +149,7 @@ int main(int argc, char **argv) {
if (!conn) {
printf("UNKNOWN - failed top open connection object.\n");
dbi_conn_close(conn);
- return STATE_UNKNOWN;
+ exit(STATE_UNKNOWN);
}
for (size_t i = 0; i < config.dbi_options_num; ++i) {
@@ -155,10 +163,10 @@ int main(int argc, char **argv) {
if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
continue;
}
- /* else: status != 0 */
- np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'",
- config.dbi_options[i].key, config.dbi_options[i].value);
+ // Failing to set option
+ np_dbi_print_error(conn, "failed to set option '%s' to '%s'", config.dbi_options[i].key,
+ config.dbi_options[i].value);
printf("Known driver options:\n");
for (opt = dbi_conn_get_option_list(conn, NULL); opt;
@@ -166,7 +174,7 @@ int main(int argc, char **argv) {
printf(" - %s\n", opt);
}
dbi_conn_close(conn);
- return STATE_UNKNOWN;
+ exit(STATE_UNKNOWN);
}
if (config.host) {
@@ -194,31 +202,60 @@ int main(int argc, char **argv) {
}
if (dbi_conn_connect(conn) < 0) {
- np_dbi_print_error(conn, "UNKNOWN - failed to connect to database");
- return STATE_UNKNOWN;
+ np_dbi_print_error(conn, "failed to connect to database");
+ exit(STATE_UNKNOWN);
}
struct timeval end_timeval;
gettimeofday(&end_timeval, NULL);
double conn_time = timediff(start_timeval, end_timeval);
+ if (verbose) {
+ printf("Time elapsed: %f\n", conn_time);
+ }
+
+ mp_check overall = mp_check_init();
+
+ mp_subcheck sc_connection_time = mp_subcheck_init();
+ sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_OK);
+ xasprintf(&sc_connection_time.output, "Connection time: %f", conn_time);
+
+ mp_perfdata pd_conn_duration = perfdata_init();
+ pd_conn_duration.label = "conntime";
+ pd_conn_duration = mp_set_pd_value(pd_conn_duration, conn_time);
+
+ if (config.metric == METRIC_CONN_TIME) {
+ // TODO set pd thresholds
+ mp_state_enum status = get_status(conn_time, config.dbi_thresholds);
+ sc_connection_time = mp_set_subcheck_state(sc_connection_time, status);
+ if (status != STATE_OK) {
+ xasprintf(&sc_connection_time.output, "%s violates thresholds",
+ sc_connection_time.output);
+ }
+ }
+
+ mp_add_perfdata_to_subcheck(&sc_connection_time, pd_conn_duration);
+ mp_add_subcheck_to_check(&overall, sc_connection_time);
unsigned int server_version = dbi_conn_get_engine_version(conn);
if (verbose) {
printf("Connected to server version %u\n", server_version);
}
- int status = STATE_UNKNOWN;
+ mp_subcheck sc_server_version = mp_subcheck_init();
+ sc_server_version = mp_set_subcheck_default_state(sc_server_version, STATE_OK);
+ xasprintf(&sc_server_version.output, "Connected to server version %u", server_version);
+
if (config.metric == METRIC_SERVER_VERSION) {
- status = get_status(server_version, config.dbi_thresholds);
- }
+ mp_state_enum status = get_status(server_version, config.dbi_thresholds);
- if (verbose) {
- printf("Time elapsed: %f\n", conn_time);
- }
+ sc_server_version = mp_set_subcheck_state(sc_server_version, status);
- if (config.metric == METRIC_CONN_TIME) {
- status = get_status(conn_time, config.dbi_thresholds);
- }
+ if (status != STATE_OK) {
+ xasprintf(&sc_server_version.output, "%s violates thresholds",
+ sc_server_version.output);
+ }
+ };
+ mp_add_subcheck_to_check(&overall, sc_server_version);
/* select a database */
if (config.dbi_database) {
@@ -226,58 +263,152 @@ int main(int argc, char **argv) {
printf("Selecting database '%s'\n", config.dbi_database);
}
+ mp_subcheck sc_select_db = mp_subcheck_init();
+ sc_select_db = mp_set_subcheck_default_state(sc_select_db, STATE_OK);
+
if (dbi_conn_select_db(conn, config.dbi_database)) {
np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'",
config.dbi_database);
- return STATE_UNKNOWN;
+ exit(STATE_UNKNOWN);
+ } else {
+ mp_add_subcheck_to_check(&overall, sc_select_db);
}
}
- const char *query_val_str = NULL;
- double query_val = 0.0;
- double query_time = 0.0;
+ // Do a query (if configured)
if (config.dbi_query) {
+ mp_subcheck sc_query = mp_subcheck_init();
+ sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN);
+
/* execute query */
- status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type,
- config.dbi_query);
- if (status != STATE_OK) {
- /* do_query prints an error message in this case */
- return status;
- }
+ do_query_result query_res = do_query(conn, config.metric, config.type, config.dbi_query);
+
+ if (query_res.error_code != 0) {
+ xasprintf(&sc_query.output, "Query failed: %s", query_res.error_string);
+ sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
+ } else if (query_res.query_processing_status != STATE_OK) {
+ if (query_res.error_string) {
+ xasprintf(&sc_query.output, "Failed to process query: %s", query_res.error_string);
+ } else {
+ xasprintf(&sc_query.output, "Failed to process query");
+ }
+ sc_query = mp_set_subcheck_state(sc_query, query_res.query_processing_status);
+ } else {
+ // query succeeded in general
+ xasprintf(&sc_query.output, "Query '%s' succeeded", config.dbi_query);
+
+ // that's a OK by default now
+ sc_query = mp_set_subcheck_default_state(sc_query, STATE_OK);
+
+ // query duration first
+ mp_perfdata pd_query_duration = perfdata_init();
+ pd_query_duration = mp_set_pd_value(pd_query_duration, query_res.query_duration);
+ pd_query_duration.label = "querytime";
+ if (config.metric == METRIC_QUERY_TIME) {
+ // TODO set thresholds
+ }
+
+ mp_add_perfdata_to_subcheck(&sc_query, pd_query_duration);
- if (config.metric == METRIC_QUERY_RESULT) {
- if (config.expect) {
- if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
- status = STATE_CRITICAL;
+ if (config.metric == METRIC_QUERY_RESULT) {
+ if (config.expect) {
+ if ((!query_res.result_string) ||
+ strcmp(query_res.result_string, config.expect)) {
+ xasprintf(&sc_query.output, "Found string '%s' in query result",
+ config.expect);
+ sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
+ } else {
+ xasprintf(&sc_query.output, "Did not find string '%s' in query result",
+ config.expect);
+ sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
+ }
+ } else if (config.expect_re_str) {
+ int comp_err;
+ regex_t expect_re = {};
+ comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags);
+ if (comp_err != 0) {
+ // TODO error, failed to compile regex
+ // TODO move this to config sanitatisation
+ printf("Failed to compile regex from string '%s'", config.expect_re_str);
+ exit(STATE_UNKNOWN);
+ }
+
+ int err =
+ regexec(&expect_re, query_res.result_string, 0, NULL, /* flags = */ 0);
+ if (!err) {
+ sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
+ xasprintf(&sc_query.output, "Found regular expression '%s' in query result",
+ config.expect_re_str);
+ } else if (err == REG_NOMATCH) {
+ sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
+ xasprintf(&sc_query.output,
+ "Did not find regular expression '%s' in query result",
+ config.expect_re_str);
+ } else {
+ char errmsg[1024];
+ regerror(err, &expect_re, errmsg, sizeof(errmsg));
+ xasprintf(&sc_query.output,
+ "ERROR - failed to execute regular expression: %s\n", errmsg);
+ sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
+ }
} else {
- status = STATE_OK;
- }
- } else if (config.expect_re_str) {
- int comp_err;
- regex_t expect_re = {};
- comp_err = regcomp(&expect_re, config.expect_re_str, config.expect_re_cflags);
- if (comp_err != 0) {
- // TODO error, failed to compile regex
- return STATE_UNKNOWN;
+ // no string matching
+ if (isnan(query_res.result_number)) {
+ // The query result is not a number, but no string checking was configured
+ // so we expected a number
+ // this is a CRITICAL
+ xasprintf(&sc_query.output, "Query '%s' result is not numeric",
+ config.dbi_query, query_res.result_string);
+ sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
+
+ } else {
+ mp_state_enum query_numerical_result =
+ get_status(query_res.result_number, config.dbi_thresholds);
+ sc_query = mp_set_subcheck_state(sc_query, query_numerical_result);
+
+ mp_perfdata pd_query_val = perfdata_init();
+ pd_query_val = mp_set_pd_value(pd_query_val, query_res.result_number);
+ pd_query_val.label = "query";
+ mp_add_perfdata_to_subcheck(&sc_query, pd_query_val);
+
+ // TODO set pd thresholds
+ // if (config.dbi_thresholds->warning) {
+ // pd_query_val.warn= config.dbi_thresholds->warning
+ // } else {
+ // }
+
+ if (query_numerical_result == STATE_OK) {
+ xasprintf(&sc_query.output,
+ "Query result '%f' is within given thresholds",
+ query_res.result_number);
+ } else {
+ xasprintf(&sc_query.output,
+ "Query result '%f' violates the given thresholds",
+ query_res.result_number);
+ }
+ }
}
-
- int err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
- if (!err) {
- status = STATE_OK;
- } else if (err == REG_NOMATCH) {
- status = STATE_CRITICAL;
+ } else if (config.metric == METRIC_QUERY_TIME) {
+ mp_state_enum query_time_status =
+ get_status(query_res.query_duration, config.dbi_thresholds);
+ mp_set_subcheck_state(sc_query, query_time_status);
+
+ if (query_time_status == STATE_OK) {
+ xasprintf(&sc_query.output, "Query duration '%f' is withing given thresholds",
+ query_res.query_duration);
} else {
- char errmsg[1024];
- regerror(err, &expect_re, errmsg, sizeof(errmsg));
- printf("ERROR - failed to execute regular expression: %s\n", errmsg);
- status = STATE_CRITICAL;
+ xasprintf(&sc_query.output, "Query duration '%f' violates the given thresholds",
+ query_res.query_duration);
}
} else {
- status = get_status(query_val, config.dbi_thresholds);
+ /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
+ * which should have been reported and handled (abort) before
+ * ... unless we expected a string to be returned */
+ assert((!isnan(query_res.result_number)) || (config.type == TYPE_STRING));
}
- } else if (config.metric == METRIC_QUERY_TIME) {
- status = get_status(query_time, config.dbi_thresholds);
}
+
+ mp_add_subcheck_to_check(&overall, sc_query);
}
if (verbose) {
@@ -285,63 +416,7 @@ int main(int argc, char **argv) {
}
dbi_conn_close(conn);
- /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
- * which should have been reported and handled (abort) before
- * ... unless we expected a string to be returned */
- assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) ||
- (config.type == TYPE_STRING));
-
- assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
-
- printf("%s - connection time: %fs", state_text(status), conn_time);
- if (config.dbi_query) {
- if (config.type == TYPE_STRING) {
- assert(config.expect || config.expect_re_str);
- printf(", '%s' returned '%s' in %fs", config.dbi_query,
- query_val_str ? query_val_str : "<nothing>", query_time);
- if (status != STATE_OK) {
- if (config.expect) {
- printf(" (expected '%s')", config.expect);
- } else if (config.expect_re_str) {
- printf(" (expected regex /%s/%s)", config.expect_re_str,
- ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
- }
- }
- } else if (isnan(query_val)) {
- printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
- } else {
- printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
- }
- }
-
- printf(
- " | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
- ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
- ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "",
- server_version,
- ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range
- : "",
- ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range
- : "");
- if (config.dbi_query) {
- if (!isnan(query_val)) { /* this is also true when -e is used */
- printf(" query=%f;%s;%s;;", query_val,
- ((config.metric == METRIC_QUERY_RESULT) && config.warning_range)
- ? config.warning_range
- : "",
- ((config.metric == METRIC_QUERY_RESULT) && config.critical_range)
- ? config.critical_range
- : "");
- }
- printf(" querytime=%fs;%s;%s;0;", query_time,
- ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range
- : "",
- ((config.metric == METRIC_QUERY_TIME) && config.critical_range)
- ? config.critical_range
- : "");
- }
- printf("\n");
- return status;
+ mp_exit(overall);
}
/* process command-line arguments */
@@ -349,7 +424,6 @@ check_dbi_config_wrapper process_arguments(int argc, char **argv) {
int option = 0;
static struct option longopts[] = {STD_LONG_OPTS,
-
{"expect", required_argument, 0, 'e'},
{"regex", required_argument, 0, 'r'},
{"regexi", required_argument, 0, 'R'},
@@ -533,6 +607,10 @@ check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrap
usage("Options -r/-R require metric QUERY_RESULT");
}
+ if (config_wrapper.config.type == TYPE_STRING) {
+ assert(config_wrapper.config.expect || config_wrapper.config.expect_re_str);
+ }
+
config_wrapper.errorcode = OK;
return config_wrapper;
}
@@ -783,38 +861,110 @@ mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_v
return STATE_OK;
}
-mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time,
- mp_dbi_metric metric, mp_dbi_type type, char *np_dbi_query) {
- dbi_result res;
-
- struct timeval timeval_start;
- struct timeval timeval_end;
- mp_state_enum status = STATE_OK;
-
- assert(np_dbi_query);
+static do_query_result do_query(dbi_conn conn, mp_dbi_metric metric, mp_dbi_type type,
+ char *query) {
+ assert(query);
if (verbose) {
- printf("Executing query '%s'\n", np_dbi_query);
+ printf("Executing query '%s'\n", query);
}
+ do_query_result result = {
+ .query_duration = 0,
+ .result_string = NULL,
+ .result_number = 0,
+ .error_code = 0,
+ .query_processing_status = STATE_UNKNOWN,
+ };
+
+ struct timeval timeval_start;
gettimeofday(&timeval_start, NULL);
- res = dbi_conn_query(conn, np_dbi_query);
+ dbi_result res = dbi_conn_query(conn, query);
if (!res) {
- np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
- return STATE_CRITICAL;
+ dbi_conn_error(conn, &result.error_string);
+ result.error_code = 1;
+ return result;
}
- status = get_query_result(conn, res, res_val_str, res_val, metric, type);
-
+ struct timeval timeval_end;
gettimeofday(&timeval_end, NULL);
- *res_time = timediff(timeval_start, timeval_end);
+ result.query_duration = timediff(timeval_start, timeval_end);
if (verbose) {
- printf("Time elapsed: %f\n", *res_time);
+ printf("Query duration: %f\n", result.query_duration);
+ }
+
+ // Default state is OK, all error will be set explicitely
+ mp_state_enum query_processing_state = STATE_OK;
+ {
+
+ if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ dbi_conn_error(conn, &result.error_string);
+ query_processing_state = STATE_CRITICAL;
+ }
+ } else if (dbi_result_get_numrows(res) < 1) {
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ result.error_string = "no rows returned";
+ // printf("WARNING - no rows returned\n");
+ query_processing_state = STATE_WARNING;
+ }
+ } else if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ dbi_conn_error(conn, &result.error_string);
+ // np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
+ query_processing_state = STATE_CRITICAL;
+ }
+ } else if (dbi_result_get_numfields(res) < 1) {
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ result.error_string = "no fields returned";
+ // printf("WARNING - no fields returned\n");
+ query_processing_state = STATE_WARNING;
+ }
+ } else if (dbi_result_first_row(res) != 1) {
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ dbi_conn_error(conn, &result.error_string);
+ // np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
+ query_processing_state = STATE_CRITICAL;
+ }
+ } else {
+ unsigned short field_type = dbi_result_get_field_type_idx(res, 1);
+ if (field_type != DBI_TYPE_ERROR) {
+ if (type == TYPE_STRING) {
+ result.result_string =
+ strdup(get_field_str(conn, res, field_type, metric, type));
+ } else {
+ result.result_number = get_field(conn, res, &field_type, metric, type);
+ }
+ } else {
+ // Error when retrieving the field, that is OK if the Query result is not of
+ // interest
+ if (metric != METRIC_QUERY_RESULT) {
+ query_processing_state = STATE_OK;
+ } else {
+ dbi_conn_error(conn, &result.error_string);
+ // np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
+ query_processing_state = STATE_CRITICAL;
+ }
+ }
+ }
}
+ dbi_result_free(res);
+
+ result.query_processing_status = query_processing_state;
- return status;
+ return result;
}
double timediff(struct timeval start, struct timeval end) {
diff --git a/plugins/t/check_dbi.t b/plugins/t/check_dbi.t
index c24b5a8c..75444de4 100644
--- a/plugins/t/check_dbi.t
+++ b/plugins/t/check_dbi.t
@@ -21,12 +21,12 @@ plan tests => $tests;
my $missing_driver_output = "failed to open DBI driver 'sqlite3'";
my $bad_driver_output = "/failed to open DBI driver 'nodriver'/";
-my $conn_time_output = "/OK - connection time: [0-9\.]+s \|/";
+my $conn_time_output = "/connection time: [0-9\.]+s \|/";
my $missing_query_output = "/Must specify a query to execute/";
-my $no_rows_output = "/WARNING - no rows returned/";
-my $not_numeric_output = "/CRITICAL - result value is not a numeric:/";
-my $query_time_output = "/OK - connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/";
-my $syntax_error_output = "/CRITICAL - failed to execute query 'GET ALL FROM test': 1: near \"GET\": syntax error/";
+my $no_rows_output = "/no rows returned/";
+my $not_numeric_output = "/result value is not a numeric:/";
+my $query_time_output = "/connection time: [0-9\.]+s, 'SELECT 1' returned 1.000000 in [0-9\.]+s \|/";
+my $syntax_error_output = "/1: near \"GET\": syntax error/";
my $result;
More information about the Commits
mailing list