
Combined functions into one which only used different default values. Removed unused functions. Used std::string where possible to make their usage easier. Hid code that isn't used externally.
536 lines
13 KiB
C++
536 lines
13 KiB
C++
/**
|
|
* @file mariadb_func.cpp - basic DB interaction routines
|
|
*
|
|
* @verbatim
|
|
* Revision History
|
|
*
|
|
* Date Who Description
|
|
* 17/11/14 Timofey Turenko Initial implementation
|
|
*
|
|
* @endverbatim
|
|
*/
|
|
|
|
|
|
#include "mariadb_func.h"
|
|
#include <ctype.h>
|
|
#include <sstream>
|
|
|
|
int set_ssl(MYSQL* conn)
|
|
{
|
|
char client_key[1024];
|
|
char client_cert[1024];
|
|
char ca[1024];
|
|
char* test_dir = getenv("test_dir");
|
|
|
|
if (test_dir == NULL)
|
|
{
|
|
sprintf(client_key, "./ssl-cert/client-key.pem");
|
|
sprintf(client_cert, "./ssl-cert/client-cert.pem");
|
|
sprintf(ca, "./ssl-cert/ca.pem");
|
|
}
|
|
else
|
|
{
|
|
sprintf(client_key, "%s/ssl-cert/client-key.pem", test_dir);
|
|
sprintf(client_cert, "%s/ssl-cert/client-cert.pem", test_dir);
|
|
sprintf(ca, "%s/ssl-cert/ca.pem", test_dir);
|
|
}
|
|
return mysql_ssl_set(conn, client_key, client_cert, ca, NULL, NULL);
|
|
}
|
|
|
|
MYSQL* open_conn_db_flags(int port, std::string ip, std::string db, std::string user, std::string password,
|
|
unsigned long flag, bool ssl)
|
|
{
|
|
MYSQL* conn = mysql_init(NULL);
|
|
|
|
if (conn == NULL)
|
|
{
|
|
fprintf(stdout, "Error: can't create MySQL-descriptor\n");
|
|
return NULL;
|
|
}
|
|
|
|
if (ssl)
|
|
{
|
|
set_ssl(conn);
|
|
}
|
|
|
|
mysql_real_connect(conn, ip.c_str(), user.c_str(), password.c_str(),
|
|
db.c_str(), port, NULL, flag);
|
|
return conn;
|
|
}
|
|
|
|
MYSQL* open_conn_db_timeout(int port, std::string ip, std::string db, std::string user, std::string password,
|
|
unsigned int timeout, bool ssl)
|
|
{
|
|
MYSQL* conn = mysql_init(NULL);
|
|
|
|
if (conn == NULL)
|
|
{
|
|
fprintf(stdout, "Error: can't create MySQL-descriptor\n");
|
|
return NULL;
|
|
}
|
|
|
|
mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
|
|
mysql_options(conn, MYSQL_OPT_READ_TIMEOUT, &timeout);
|
|
mysql_options(conn, MYSQL_OPT_WRITE_TIMEOUT, &timeout);
|
|
|
|
if (ssl)
|
|
{
|
|
set_ssl(conn);
|
|
}
|
|
|
|
mysql_real_connect(conn, ip.c_str(), user.c_str(), password.c_str(),
|
|
db.c_str(), port, NULL, CLIENT_MULTI_STATEMENTS);
|
|
return conn;
|
|
}
|
|
|
|
int execute_query(MYSQL* conn, const char* format, ...)
|
|
{
|
|
va_list valist;
|
|
|
|
va_start(valist, format);
|
|
int message_len = vsnprintf(NULL, 0, format, valist);
|
|
va_end(valist);
|
|
|
|
char sql[message_len + 1];
|
|
|
|
va_start(valist, format);
|
|
vsnprintf(sql, sizeof(sql), format, valist);
|
|
va_end(valist);
|
|
|
|
return execute_query_silent(conn, sql, false);
|
|
}
|
|
|
|
int execute_query_from_file(MYSQL* conn, FILE* file)
|
|
{
|
|
int rc = -1;
|
|
char buf[4096];
|
|
|
|
if (fgets(buf, sizeof(buf), file))
|
|
{
|
|
char *nul = strchr(buf, '\0') - 1;
|
|
|
|
while (isspace(*nul))
|
|
{
|
|
*nul-- = '\0';
|
|
}
|
|
|
|
char *ptr = buf;
|
|
|
|
while (isspace(*ptr))
|
|
{
|
|
ptr++;
|
|
}
|
|
|
|
if (*ptr)
|
|
{
|
|
rc = execute_query_silent(conn, buf, false);
|
|
}
|
|
|
|
}
|
|
else if (!feof(file))
|
|
{
|
|
printf("Failed to read file: %d, %s", errno, strerror(errno));
|
|
rc = 1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int execute_query_silent(MYSQL* conn, const char* sql, bool silent)
|
|
{
|
|
MYSQL_RES *res;
|
|
if (conn != NULL)
|
|
{
|
|
if (mysql_query(conn, sql) != 0)
|
|
{
|
|
if (!silent)
|
|
{
|
|
int len = strlen(sql);
|
|
printf("Error: can't execute SQL-query: %.*s\n", len < 60 ? len : 60, sql);
|
|
printf("%s\n\n", mysql_error(conn));
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
res = mysql_store_result(conn);
|
|
mysql_free_result(res);
|
|
}
|
|
while ( mysql_next_result(conn) == 0 );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!silent)
|
|
{
|
|
printf("Connection is broken\n");
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int execute_query_check_one(MYSQL* conn, const char* sql, const char* expected)
|
|
{
|
|
int r = 1;
|
|
|
|
if (conn != NULL)
|
|
{
|
|
const int n_attempts = 3;
|
|
|
|
for (int i = 0; i < n_attempts && r != 0; i++)
|
|
{
|
|
if (i > 0)
|
|
{
|
|
sleep(1);
|
|
}
|
|
|
|
if (mysql_query(conn, sql) != 0)
|
|
{
|
|
printf("Error: can't execute SQL-query: %s\n", sql);
|
|
printf("%s\n\n", mysql_error(conn));
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
MYSQL_RES *res = mysql_store_result(conn);
|
|
|
|
if (res)
|
|
{
|
|
if (mysql_num_rows(res) == 1)
|
|
{
|
|
MYSQL_ROW row = mysql_fetch_row(res);
|
|
|
|
if (row[0] != NULL)
|
|
{
|
|
if (strcmp(row[0], expected) == 0)
|
|
{
|
|
r = 0;
|
|
printf("First field is '%s' as expected\n", row[0]);
|
|
}
|
|
else
|
|
{
|
|
printf("First field is '%s, but expected %s'\n", row[0], expected);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("First field is NULL\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Number of rows is not 1, it is %llu\n", mysql_num_rows(res));
|
|
}
|
|
|
|
mysql_free_result(res);
|
|
}
|
|
}
|
|
while (mysql_next_result(conn) == 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Connection is broken\n");
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
int execute_query_affected_rows(MYSQL* conn, const char* sql, my_ulonglong* affected_rows)
|
|
{
|
|
MYSQL_RES *res;
|
|
if (conn != NULL)
|
|
{
|
|
if (mysql_query(conn, sql) != 0)
|
|
{
|
|
printf("Error: can't execute SQL-query: %s\n", sql);
|
|
printf("%s\n\n", mysql_error(conn));
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
*affected_rows = mysql_affected_rows(conn);
|
|
res = mysql_store_result(conn);
|
|
mysql_free_result(res);
|
|
}
|
|
while ( mysql_next_result(conn) == 0 );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Connection is broken\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int execute_query_num_of_rows(MYSQL* conn, const char* sql, my_ulonglong* num_of_rows,
|
|
unsigned long long* i)
|
|
{
|
|
MYSQL_RES *res;
|
|
my_ulonglong N;
|
|
|
|
|
|
printf("%s\n", sql);
|
|
if (conn != NULL)
|
|
{
|
|
if (mysql_query(conn, sql) != 0)
|
|
{
|
|
printf("Error: can't execute SQL-query: %s\n", sql);
|
|
printf("%s\n\n", mysql_error(conn));
|
|
* i = 0;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
*i = 0;
|
|
do
|
|
{
|
|
res = mysql_store_result(conn);
|
|
if (res != NULL)
|
|
{
|
|
N = mysql_num_rows(res);
|
|
mysql_free_result(res);
|
|
}
|
|
else
|
|
{
|
|
N = 0;
|
|
}
|
|
num_of_rows[*i] = N;
|
|
*i = *i + 1;
|
|
}
|
|
while ( mysql_next_result(conn) == 0 );
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Connection is broken\n");
|
|
* i = 0;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int execute_stmt_num_of_rows(MYSQL_STMT* stmt, my_ulonglong* num_of_rows, unsigned long long* i)
|
|
{
|
|
my_ulonglong N;
|
|
|
|
/* This is debug hack; compatible only with t1 from t1_sql.h
|
|
my_ulonglong k;
|
|
MYSQL_BIND bind[2];
|
|
my_ulonglong x1;
|
|
my_ulonglong fl;
|
|
|
|
unsigned long length[2];
|
|
my_bool is_null[2];
|
|
my_bool error[2];
|
|
|
|
memset(bind, 0, sizeof(bind));
|
|
bind[0].buffer = &x1;
|
|
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
|
bind[0].length = &length[0];
|
|
bind[0].is_null = &is_null[0];
|
|
bind[0].error = &error[0];
|
|
|
|
bind[1].buffer = &fl;
|
|
bind[1].buffer_type = MYSQL_TYPE_LONG;
|
|
bind[1].length = &length[0];
|
|
bind[1].is_null = &is_null[0];
|
|
bind[1].error = &error[0];
|
|
*/
|
|
|
|
if (mysql_stmt_execute(stmt) != 0)
|
|
{
|
|
printf("Error: can't execute prepared statement\n");
|
|
printf("%s\n\n", mysql_stmt_error(stmt));
|
|
* i = 0;
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
*i = 0;
|
|
do
|
|
{
|
|
mysql_stmt_store_result(stmt);
|
|
N = mysql_stmt_num_rows(stmt);
|
|
/* This is debug hack; compatible only with t1 from t1_sql.h
|
|
mysql_stmt_bind_result(stmt, bind);
|
|
for (k = 0; k < N; k++)
|
|
{
|
|
mysql_stmt_fetch(stmt);
|
|
printf("%04llu: x1 %llu, fl %llu\n", k, x1, fl);
|
|
}
|
|
*/
|
|
num_of_rows[*i] = N;
|
|
*i = *i + 1;
|
|
|
|
}
|
|
while ( mysql_stmt_next_result(stmt) == 0 );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int execute_query_count_rows(MYSQL* conn, const char* sql)
|
|
{
|
|
int rval = -1;
|
|
|
|
unsigned long long num_of_rows[1024];
|
|
unsigned long long total;
|
|
|
|
if (execute_query_num_of_rows(conn, sql, num_of_rows, &total) == 0)
|
|
{
|
|
rval = 0;
|
|
|
|
for (int i = 0; i < total && i < 1024; i++)
|
|
{
|
|
rval += num_of_rows[i];
|
|
}
|
|
}
|
|
|
|
return rval;
|
|
}
|
|
|
|
int get_conn_num(MYSQL* conn, std::string ip, std::string hostname, std::string db)
|
|
{
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
unsigned long long int num_fields;
|
|
unsigned long long int rows;
|
|
unsigned long long int i;
|
|
unsigned int conn_num = 0;
|
|
const char* hostname_internal;
|
|
|
|
if (ip == "127.0.0.1")
|
|
{
|
|
hostname_internal = "localhost";
|
|
}
|
|
else
|
|
{
|
|
hostname_internal = hostname.c_str();
|
|
}
|
|
|
|
if (conn != NULL)
|
|
{
|
|
if (mysql_query(conn, "show processlist;") != 0)
|
|
{
|
|
printf("Error: can't execute SQL-query: show processlist\n");
|
|
printf("%s\n\n", mysql_error(conn));
|
|
conn_num = 0;
|
|
}
|
|
else
|
|
{
|
|
res = mysql_store_result(conn);
|
|
if (res == NULL)
|
|
{
|
|
printf("Error: can't get the result description\n");
|
|
conn_num = -1;
|
|
}
|
|
else
|
|
{
|
|
num_fields = mysql_num_fields(res);
|
|
rows = mysql_num_rows(res);
|
|
for (i = 0; i < rows; i++)
|
|
{
|
|
row = mysql_fetch_row(res);
|
|
if ( (row[2] != NULL ) && (row[3] != NULL) )
|
|
{
|
|
if ((strstr(row[2], ip.c_str()) != NULL) && (strstr(row[3], db.c_str()) != NULL))
|
|
{
|
|
conn_num++;
|
|
}
|
|
if ((strstr(row[2], hostname_internal) != NULL) && (strstr(row[3], db.c_str()) != NULL))
|
|
{
|
|
conn_num++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
mysql_free_result(res);
|
|
}
|
|
}
|
|
if (ip == "127.0.0.1")
|
|
{
|
|
// one extra connection is visible in the process list
|
|
// output in case of local test
|
|
// (when MaxScale is on the same machine as backends)
|
|
conn_num--;
|
|
}
|
|
return conn_num;
|
|
}
|
|
|
|
int find_field(MYSQL* conn, const char* sql, const char* field_name, char* value)
|
|
{
|
|
MYSQL_RES *res;
|
|
MYSQL_ROW row;
|
|
MYSQL_FIELD *field;
|
|
unsigned long long int num_fields;
|
|
unsigned int ret = 1;
|
|
unsigned long long int filed_i = 0;
|
|
unsigned long long int i = 0;
|
|
|
|
if (conn != NULL )
|
|
{
|
|
if (mysql_query(conn, sql) != 0)
|
|
{
|
|
printf("Error: can't execute SQL-query: %s\n", sql);
|
|
printf("%s\n\n", mysql_error(conn));
|
|
}
|
|
else
|
|
{
|
|
res = mysql_store_result(conn);
|
|
if (res == NULL)
|
|
{
|
|
printf("Error: can't get the result description\n");
|
|
}
|
|
else
|
|
{
|
|
num_fields = mysql_num_fields(res);
|
|
|
|
while ((field = mysql_fetch_field(res)) && ret != 0)
|
|
{
|
|
if (strstr(field->name, field_name) != NULL)
|
|
{
|
|
filed_i = i;
|
|
ret = 0;
|
|
}
|
|
i++;
|
|
}
|
|
if (mysql_num_rows(res) > 0)
|
|
{
|
|
row = mysql_fetch_row(res);
|
|
sprintf(value, "%s", row[filed_i]);
|
|
}
|
|
}
|
|
mysql_free_result(res);
|
|
do
|
|
{
|
|
res = mysql_store_result(conn);
|
|
mysql_free_result(res);
|
|
}
|
|
while ( mysql_next_result(conn) == 0 );
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int get_int_version(std::string version)
|
|
{
|
|
std::istringstream str(version);
|
|
int major = 0;
|
|
int minor = 0;
|
|
int patch = 0;
|
|
char dot;
|
|
|
|
str >> major >> dot >> minor >> dot >> patch;
|
|
return major * 10000 + minor * 100 + patch;
|
|
}
|