MXS-1703 Add convenience function + class for querying and storing results
An object of the class is returned as an auto_ptr to simplify memory management.
This commit is contained in:
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <maxscale/mysql_utils.h>
|
||||||
#include "utilities.hh"
|
#include "utilities.hh"
|
||||||
|
|
||||||
Gtid::Gtid()
|
Gtid::Gtid()
|
||||||
@ -116,3 +116,18 @@ int64_t MariaDBServer::relay_log_events()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::auto_ptr<QueryResult> MariaDBServer::execute_query(const string& query)
|
||||||
|
{
|
||||||
|
auto conn = server_base->con;
|
||||||
|
std::auto_ptr<QueryResult> rval;
|
||||||
|
MYSQL_RES *result = NULL;
|
||||||
|
if (mxs_mysql_query(conn, query.c_str()) == 0 && (result = mysql_store_result(conn)) != NULL)
|
||||||
|
{
|
||||||
|
rval = std::auto_ptr<QueryResult>(new QueryResult(result));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mon_report_query_error(server_base);
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
@ -16,10 +16,10 @@
|
|||||||
#include <maxscale/cppdefs.hh>
|
#include <maxscale/cppdefs.hh>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
#include <maxscale/monitor.h>
|
#include <maxscale/monitor.h>
|
||||||
|
#include "utilities.hh"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
enum mysql_server_version
|
enum mysql_server_version
|
||||||
{
|
{
|
||||||
MYSQL_SERVER_VERSION_100,
|
MYSQL_SERVER_VERSION_100,
|
||||||
@ -47,7 +47,7 @@ public:
|
|||||||
|
|
||||||
bool operator == (const Gtid& rhs) const;
|
bool operator == (const Gtid& rhs) const;
|
||||||
|
|
||||||
string to_string() const;
|
std::string to_string() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a MASTER_GTID_WAIT()-query to this gtid.
|
* Generate a MASTER_GTID_WAIT()-query to this gtid.
|
||||||
@ -55,7 +55,7 @@ public:
|
|||||||
* @param timeout Maximum wait time in seconds
|
* @param timeout Maximum wait time in seconds
|
||||||
* @return The query
|
* @return The query
|
||||||
*/
|
*/
|
||||||
string generate_master_gtid_wait_cmd(double timeout) const;
|
std::string generate_master_gtid_wait_cmd(double timeout) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parse_triplet(const char* str);
|
void parse_triplet(const char* str);
|
||||||
@ -67,17 +67,17 @@ class SlaveStatusInfo
|
|||||||
public:
|
public:
|
||||||
int64_t master_server_id; /**< The master's server_id value. Valid ids are 32bit unsigned. -1 is
|
int64_t master_server_id; /**< The master's server_id value. Valid ids are 32bit unsigned. -1 is
|
||||||
* unread/error. */
|
* unread/error. */
|
||||||
string master_host; /**< Master server host name. */
|
std::string master_host; /**< Master server host name. */
|
||||||
int master_port; /**< Master server port. */
|
int master_port; /**< Master server port. */
|
||||||
bool slave_io_running; /**< Whether the slave I/O thread is running and connected. */
|
bool slave_io_running; /**< Whether the slave I/O thread is running and connected. */
|
||||||
bool slave_sql_running; /**< Whether or not the SQL thread is running. */
|
bool slave_sql_running; /**< Whether or not the SQL thread is running. */
|
||||||
string master_log_file; /**< Name of the master binary log file that the I/O thread is currently
|
std::string master_log_file; /**< Name of the master binary log file that the I/O thread is currently
|
||||||
* reading from. */
|
* reading from. */
|
||||||
uint64_t read_master_log_pos; /**< Position up to which the I/O thread has read in the current master
|
uint64_t read_master_log_pos; /**< Position up to which the I/O thread has read in the current master
|
||||||
* binary log file. */
|
* binary log file. */
|
||||||
Gtid gtid_io_pos; /**< Gtid I/O position of the slave thread. Only shows the triplet with
|
Gtid gtid_io_pos; /**< Gtid I/O position of the slave thread. Only shows the triplet with
|
||||||
* the current master domain. */
|
* the current master domain. */
|
||||||
string last_error; /**< Last IO or SQL error encountered. */
|
std::string last_error; /**< Last IO or SQL error encountered. */
|
||||||
|
|
||||||
SlaveStatusInfo();
|
SlaveStatusInfo();
|
||||||
};
|
};
|
||||||
@ -137,4 +137,14 @@ public:
|
|||||||
* an error in the gtid-values.
|
* an error in the gtid-values.
|
||||||
*/
|
*/
|
||||||
int64_t relay_log_events();
|
int64_t relay_log_events();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a query which returns data. The results are returned as an auto-pointer to a QueryResult
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @param query The query
|
||||||
|
* @return Pointer to query results, or an empty auto-ptr on failure. Currently, the column names of the
|
||||||
|
* results are assumed unique.
|
||||||
|
*/
|
||||||
|
std::auto_ptr<QueryResult> execute_query(const std::string& query);
|
||||||
};
|
};
|
||||||
@ -113,3 +113,81 @@ string monitored_servers_to_string(const ServerVector& array)
|
|||||||
}
|
}
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QueryResult::QueryResult(MYSQL_RES* resultset)
|
||||||
|
: m_resultset(resultset)
|
||||||
|
, m_columns(-1)
|
||||||
|
, m_rowdata(NULL)
|
||||||
|
, m_current_row(-1)
|
||||||
|
{
|
||||||
|
if (m_resultset)
|
||||||
|
{
|
||||||
|
m_columns = mysql_num_fields(m_resultset);
|
||||||
|
MYSQL_FIELD* field_info = mysql_fetch_fields(m_resultset);
|
||||||
|
for (int64_t column_index = 0; column_index < m_columns; column_index++)
|
||||||
|
{
|
||||||
|
string key(field_info[column_index].name);
|
||||||
|
// TODO: Think of a way to handle duplicate names nicely. Currently this should only be used
|
||||||
|
// for known queries.
|
||||||
|
ss_dassert(m_col_indexes.count(key) == 0);
|
||||||
|
m_col_indexes[key] = column_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult::~QueryResult()
|
||||||
|
{
|
||||||
|
if (m_resultset)
|
||||||
|
{
|
||||||
|
mysql_free_result(m_resultset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QueryResult::next_row()
|
||||||
|
{
|
||||||
|
m_rowdata = mysql_fetch_row(m_resultset);
|
||||||
|
if (m_rowdata != NULL)
|
||||||
|
{
|
||||||
|
m_current_row++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t QueryResult::get_row_index() const
|
||||||
|
{
|
||||||
|
return m_current_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t QueryResult::get_column_count() const
|
||||||
|
{
|
||||||
|
return m_columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t QueryResult::get_col_index(const string& col_name) const
|
||||||
|
{
|
||||||
|
auto iter = m_col_indexes.find(col_name);
|
||||||
|
return (iter != m_col_indexes.end()) ? iter->second : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
string QueryResult::get_string(int64_t column_ind) const
|
||||||
|
{
|
||||||
|
ss_dassert(column_ind < m_columns);
|
||||||
|
char* data = m_rowdata[column_ind];
|
||||||
|
return data ? data : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t QueryResult::get_int(int64_t column_ind) const
|
||||||
|
{
|
||||||
|
ss_dassert(column_ind < m_columns);
|
||||||
|
char* data = m_rowdata[column_ind];
|
||||||
|
errno = 0; // strtoll sets this
|
||||||
|
return data ? strtoll(data, NULL, 10) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QueryResult::get_bool(int64_t column_ind) const
|
||||||
|
{
|
||||||
|
ss_dassert(column_ind < m_columns);
|
||||||
|
char* data = m_rowdata[column_ind];
|
||||||
|
return data ? (strcmp(data,"Y") == 0 || strcmp(data, "1") == 0) : false;
|
||||||
|
}
|
||||||
|
|||||||
@ -71,3 +71,79 @@ string get_connection_errors(const ServerVector& servers);
|
|||||||
* @return Server names
|
* @return Server names
|
||||||
*/
|
*/
|
||||||
string monitored_servers_to_string(const ServerVector& array);
|
string monitored_servers_to_string(const ServerVector& array);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for simplifying working with resultsets. Used in MariaDBServer.
|
||||||
|
*/
|
||||||
|
class QueryResult
|
||||||
|
{
|
||||||
|
// These need to be banned to avoid premature destruction.
|
||||||
|
QueryResult(const QueryResult&) = delete;
|
||||||
|
QueryResult& operator = (const QueryResult&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QueryResult(MYSQL_RES* resultset = NULL);
|
||||||
|
~QueryResult();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Advance to next row. Affects all result returning functions.
|
||||||
|
*
|
||||||
|
* @return True if the next row has data, false if the current row was the last one.
|
||||||
|
*/
|
||||||
|
bool next_row();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the current row.
|
||||||
|
*
|
||||||
|
* @return Current row index, or -1 if no data or next_row() has not been called yet.
|
||||||
|
*/
|
||||||
|
int64_t get_row_index() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many columns the result set has.
|
||||||
|
*
|
||||||
|
* @return Column count, or -1 if no data.
|
||||||
|
*/
|
||||||
|
int64_t get_column_count() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a numeric index for a column name. May give wrong results if column names are not unique.
|
||||||
|
*
|
||||||
|
* @param col_name Column name
|
||||||
|
* @return Index or -1 if not found.
|
||||||
|
*/
|
||||||
|
int64_t get_col_index(const string& col_name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a string value from the current row and given column. Empty string and (null) are both interpreted
|
||||||
|
* as the empty string.
|
||||||
|
*
|
||||||
|
* @param column_ind Column index
|
||||||
|
* @return Value as string
|
||||||
|
*/
|
||||||
|
string get_string(int64_t column_ind) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an integer value from the current row and given column. No error checking is done on the parsing.
|
||||||
|
* The parsing is performed by @c strtoll(), so the caller may check errno for errors.
|
||||||
|
*
|
||||||
|
* @param column_ind Column index
|
||||||
|
* @return Value as integer
|
||||||
|
*/
|
||||||
|
int64_t get_int(int64_t column_ind) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a boolean value from the current row and given column.
|
||||||
|
*
|
||||||
|
* @param column_ind Column index
|
||||||
|
* @return Value as boolean. Returns true if the text is either 'Y' or '1'.
|
||||||
|
*/
|
||||||
|
bool get_bool(int64_t column_ind) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MYSQL_RES* m_resultset; // Underlying result set, freed at dtor.
|
||||||
|
std::tr1::unordered_map<string, int64_t> m_col_indexes; // Map of column name -> index
|
||||||
|
int64_t m_columns; // How many columns does the data have. Usually equal to column index map size.
|
||||||
|
MYSQL_ROW m_rowdata; // Data for current row
|
||||||
|
int64_t m_current_row; // Index of current row
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user