int udb_query_prepare_result (udb_query_t *q, /* {{{ */ const char *host, const char *plugin, const char *db_name, char **column_names, size_t column_num) { udb_result_t *r; int status; if (q == NULL) return (-EINVAL); udb_query_finish_result (q); q->column_num = column_num; q->host = strdup (host); q->plugin = strdup (plugin); q->db_name = strdup (db_name); if ((q->host == NULL) || (q->plugin == NULL) || (q->db_name == NULL)) { ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name); udb_query_finish_result (q); return (-ENOMEM); } #if defined(COLLECT_DEBUG) && COLLECT_DEBUG do { size_t i; for (i = 0; i < column_num; i++) { DEBUG ("db query utils: udb_query_prepare_result: " "query = %s; column[%zu] = %s;", q->name, i, column_names[i]); } } while (0); #endif for (r = q->results; r != NULL; r = r->next) { status = udb_result_prepare_result (r, column_names, column_num); if (status != 0) { udb_query_finish_result (q); return (status); } } return (0); } /* }}} int udb_query_prepare_result */
static int c_psql_exec_query (c_psql_database_t *db, udb_query_t *q, udb_query_preparation_area_t *prep_area) { PGresult *res; c_psql_user_data_t *data; const char *host; char **column_names; char **column_values; int column_num; int rows_num; int status; int row, col; /* The user data may hold parameter information, but may be NULL. */ data = udb_query_get_user_data (q); /* Versions up to `3' don't know how to handle parameters. */ if (3 <= db->proto_version) res = c_psql_exec_query_params (db, q, data); else if ((NULL == data) || (0 == data->params_num)) res = c_psql_exec_query_noparams (db, q); else { log_err ("Connection to database \"%s\" (%s) does not support " "parameters (protocol version %d) - " "cannot execute query \"%s\".", db->database, db->instance, db->proto_version, udb_query_get_name (q)); return -1; } column_names = NULL; column_values = NULL; #define BAIL_OUT(status) \ sfree (column_names); \ sfree (column_values); \ PQclear (res); \ return status if (PGRES_TUPLES_OK != PQresultStatus (res)) { log_err ("Failed to execute SQL query: %s", PQerrorMessage (db->conn)); log_info ("SQL query was: %s", udb_query_get_statement (q)); BAIL_OUT (-1); } rows_num = PQntuples (res); if (1 > rows_num) { BAIL_OUT (0); } column_num = PQnfields (res); column_names = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_names) { log_err ("calloc failed."); BAIL_OUT (-1); } column_values = (char **) calloc (column_num, sizeof (char *)); if (NULL == column_values) { log_err ("calloc failed."); BAIL_OUT (-1); } for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQfname' are freed by `PQclear' via * `BAIL_OUT'. */ column_names[col] = PQfname (res, col); if (NULL == column_names[col]) { log_err ("Failed to resolve name of column %i.", col); BAIL_OUT (-1); } } if (C_PSQL_IS_UNIX_DOMAIN_SOCKET (db->host) || (0 == strcmp (db->host, "localhost"))) host = hostname_g; else host = db->host; status = udb_query_prepare_result (q, prep_area, host, "postgresql", db->instance, column_names, (size_t) column_num, db->interval); if (0 != status) { log_err ("udb_query_prepare_result failed with status %i.", status); BAIL_OUT (-1); } for (row = 0; row < rows_num; ++row) { for (col = 0; col < column_num; ++col) { /* Pointers returned by `PQgetvalue' are freed by `PQclear' via * `BAIL_OUT'. */ column_values[col] = PQgetvalue (res, row, col); if (NULL == column_values[col]) { log_err ("Failed to get value at (row = %i, col = %i).", row, col); break; } } /* check for an error */ if (col < column_num) continue; status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { log_err ("udb_query_handle_result failed with status %i.", status); } } /* for (row = 0; row < rows_num; ++row) */ udb_query_finish_result (q, prep_area); BAIL_OUT (0); #undef BAIL_OUT } /* c_psql_exec_query */
static int cdbi_read_database_query (cdbi_database_t *db, /* {{{ */ udb_query_t *q, udb_query_preparation_area_t *prep_area) { const char *statement; dbi_result res; size_t column_num; char **column_names; char **column_values; int status; size_t i; /* Macro that cleans up dynamically allocated memory and returns the * specified status. */ #define BAIL_OUT(status) \ if (column_names != NULL) { sfree (column_names[0]); sfree (column_names); } \ if (column_values != NULL) { sfree (column_values[0]); sfree (column_values); } \ if (res != NULL) { dbi_result_free (res); res = NULL; } \ return (status) column_names = NULL; column_values = NULL; statement = udb_query_get_statement (q); assert (statement != NULL); res = dbi_conn_query (db->connection, statement); if (res == NULL) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_conn_query failed: %s", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); BAIL_OUT (-1); } else /* Get the number of columns */ { unsigned int db_status; db_status = dbi_result_get_numfields (res); if (db_status == DBI_FIELD_ERROR) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_get_numfields failed: %s", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); BAIL_OUT (-1); } column_num = (size_t) db_status; DEBUG ("cdbi_read_database_query (%s, %s): There are %zu columns.", db->name, udb_query_get_name (q), column_num); } /* Allocate `column_names' and `column_values'. {{{ */ column_names = calloc (column_num, sizeof (*column_names)); if (column_names == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } column_names[0] = calloc (column_num, DATA_MAX_NAME_LEN); if (column_names[0] == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } for (i = 1; i < column_num; i++) column_names[i] = column_names[i - 1] + DATA_MAX_NAME_LEN; column_values = calloc (column_num, sizeof (*column_values)); if (column_values == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } column_values[0] = calloc (column_num, DATA_MAX_NAME_LEN); if (column_values[0] == NULL) { ERROR ("dbi plugin: calloc failed."); BAIL_OUT (-1); } for (i = 1; i < column_num; i++) column_values[i] = column_values[i - 1] + DATA_MAX_NAME_LEN; /* }}} */ /* Copy the field names to `column_names' */ for (i = 0; i < column_num; i++) /* {{{ */ { const char *column_name; column_name = dbi_result_get_field_name (res, (unsigned int) (i + 1)); if (column_name == NULL) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "Cannot retrieve name of field %zu.", db->name, udb_query_get_name (q), i + 1); BAIL_OUT (-1); } sstrncpy (column_names[i], column_name, DATA_MAX_NAME_LEN); } /* }}} for (i = 0; i < column_num; i++) */ udb_query_prepare_result (q, prep_area, (db->host ? db->host : hostname_g), /* plugin = */ "dbi", db->name, column_names, column_num, /* interval = */ (db->interval > 0) ? db->interval : 0); /* 0 = error; 1 = success; */ status = dbi_result_first_row (res); /* {{{ */ if (status != 1) { char errbuf[1024]; ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_first_row failed: %s. Maybe the statement didn't " "return any rows?", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); udb_query_finish_result (q, prep_area); BAIL_OUT (-1); } /* }}} */ /* Iterate over all rows and call `udb_query_handle_result' with each list of * values. */ while (42) /* {{{ */ { status = 0; /* Copy the value of the columns to `column_values' */ for (i = 0; i < column_num; i++) /* {{{ */ { status = cdbi_result_get_field (res, (unsigned int) (i + 1), column_values[i], DATA_MAX_NAME_LEN); if (status != 0) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "cdbi_result_get_field (%zu) failed.", db->name, udb_query_get_name (q), i + 1); status = -1; break; } } /* }}} for (i = 0; i < column_num; i++) */ /* If all values were copied successfully, call `udb_query_handle_result' * to dispatch the row to the daemon. */ if (status == 0) /* {{{ */ { status = udb_query_handle_result (q, prep_area, column_values); if (status != 0) { ERROR ("dbi plugin: cdbi_read_database_query (%s, %s): " "udb_query_handle_result failed.", db->name, udb_query_get_name (q)); } } /* }}} */ /* Get the next row from the database. */ status = dbi_result_next_row (res); /* {{{ */ if (status != 1) { if (dbi_conn_error (db->connection, NULL) != 0) { char errbuf[1024]; WARNING ("dbi plugin: cdbi_read_database_query (%s, %s): " "dbi_result_next_row failed: %s.", db->name, udb_query_get_name (q), cdbi_strerror (db->connection, errbuf, sizeof (errbuf))); } break; } /* }}} */ } /* }}} while (42) */ /* Tell the db query interface that we're done with this query. */ udb_query_finish_result (q, prep_area); /* Clean up and return `status = 0' (success) */ BAIL_OUT (0); #undef BAIL_OUT } /* }}} int cdbi_read_database_query */
int udb_query_prepare_result (udb_query_t const *q, /* {{{ */ udb_query_preparation_area_t *prep_area, const char *host, const char *plugin, const char *db_name, char **column_names, size_t column_num, cdtime_t interval) { udb_result_preparation_area_t *r_area; udb_result_t *r; int status; if ((q == NULL) || (prep_area == NULL)) return (-EINVAL); udb_query_finish_result (q, prep_area); prep_area->column_num = column_num; prep_area->host = strdup (host); prep_area->plugin = strdup (plugin); prep_area->db_name = strdup (db_name); prep_area->interval = interval; if ((prep_area->host == NULL) || (prep_area->plugin == NULL) || (prep_area->db_name == NULL)) { ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name); udb_query_finish_result (q, prep_area); return (-ENOMEM); } #if defined(COLLECT_DEBUG) && COLLECT_DEBUG do { size_t i; for (i = 0; i < column_num; i++) { DEBUG ("db query utils: udb_query_prepare_result: " "query = %s; column[%zu] = %s;", q->name, i, column_names[i]); } } while (0); #endif /* Determine the position of the PluginInstance column {{{ */ if (q->plugin_instance_from != NULL) { size_t i; for (i = 0; i < column_num; i++) { if (strcasecmp (q->plugin_instance_from, column_names[i]) == 0) { prep_area->plugin_instance_pos = i; break; } } if (i >= column_num) { ERROR ("db query utils: udb_query_prepare_result: " "Column `%s' from `PluginInstanceFrom' could not be found.", q->plugin_instance_from); udb_query_finish_result (q, prep_area); return (-ENOENT); } } /* }}} */ for (r = q->results, r_area = prep_area->result_prep_areas; r != NULL; r = r->next, r_area = r_area->next) { if (! r_area) { ERROR ("db query utils: Query `%s': Invalid number of result " "preparation areas.", q->name); udb_query_finish_result (q, prep_area); return (-EINVAL); } status = udb_result_prepare_result (r, r_area, column_names, column_num); if (status != 0) { udb_query_finish_result (q, prep_area); return (status); } } return (0); } /* }}} int udb_query_prepare_result */
int udb_query_prepare_result (const udb_query_t const *q, /* {{{ */ udb_query_preparation_area_t *prep_area, const char *host, const char *plugin, const char *db_name, char **column_names, size_t column_num, int interval) { udb_result_preparation_area_t *r_area; udb_result_t *r; int status; if ((q == NULL) || (prep_area == NULL)) return (-EINVAL); udb_query_finish_result (q, prep_area); prep_area->column_num = column_num; prep_area->host = strdup (host); prep_area->plugin = strdup (plugin); prep_area->db_name = strdup (db_name); prep_area->interval = interval; if ((prep_area->host == NULL) || (prep_area->plugin == NULL) || (prep_area->db_name == NULL)) { ERROR ("db query utils: Query `%s': Prepare failed: Out of memory.", q->name); udb_query_finish_result (q, prep_area); return (-ENOMEM); } #if defined(COLLECT_DEBUG) && COLLECT_DEBUG do { size_t i; for (i = 0; i < column_num; i++) { DEBUG ("db query utils: udb_query_prepare_result: " "query = %s; column[%zu] = %s;", q->name, i, column_names[i]); } } while (0); #endif for (r = q->results, r_area = prep_area->result_prep_areas; r != NULL; r = r->next, r_area = r_area->next) { if (! r_area) { ERROR ("db query utils: Query `%s': Invalid number of result " "preparation areas.", q->name); udb_query_finish_result (q, prep_area); return (-EINVAL); } status = udb_result_prepare_result (r, r_area, column_names, column_num); if (status != 0) { udb_query_finish_result (q, prep_area); return (status); } } return (0); } /* }}} int udb_query_prepare_result */