summaryrefslogtreecommitdiff
path: root/storage/ndb/test/src/DbUtil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/test/src/DbUtil.cpp')
-rwxr-xr-xstorage/ndb/test/src/DbUtil.cpp546
1 files changed, 443 insertions, 103 deletions
diff --git a/storage/ndb/test/src/DbUtil.cpp b/storage/ndb/test/src/DbUtil.cpp
index 5fe3e6e9fbe..a52f45b46a7 100755
--- a/storage/ndb/test/src/DbUtil.cpp
+++ b/storage/ndb/test/src/DbUtil.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 MySQL AB
+/* Copyright (C) 2008 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,43 +16,89 @@
/* DbUtil.cpp: implementation of the database utilities class.*/
#include "DbUtil.hpp"
+#include <NdbSleep.h>
-/* Constructors */
-DbUtil::DbUtil(const char * dbname)
-{
- m_port = 0;
- m_connected = false;
- this->setDbName(dbname);
-}
+/* Constructors */
-DbUtil::DbUtil(const char * dbname, const char* suffix)
+DbUtil::DbUtil(const char* _dbname,
+ const char* _user,
+ const char* _password,
+ const char* _suffix):
+ m_connected(false),
+ m_dbname(_dbname),
+ m_mysql(NULL),
+ m_free_mysql(true)
{
- this->setDbName(dbname);
- m_connected = false;
-
const char* env= getenv("MYSQL_HOME");
if (env && strlen(env))
{
- default_file.assfmt("%s/my.cnf", env);
+ m_default_file.assfmt("%s/my.cnf", env);
}
- if (suffix != NULL){
- default_group.assfmt("client%s", suffix);
+ if (_suffix != NULL){
+ m_default_group.assfmt("client%s", _suffix);
}
else {
- default_group.assign("client.1.master");
+ m_default_group.assign("client.1.master");
+ }
+
+ ndbout << "default_file: " << m_default_file.c_str() << endl;
+ ndbout << "default_group: " << m_default_group.c_str() << endl;
+
+ m_user.assign(_user);
+ m_pass.assign(_password);
+}
+
+
+
+DbUtil::DbUtil(MYSQL* mysql):
+ m_connected(true),
+ m_mysql(mysql),
+ m_free_mysql(false)
+{
+}
+
+
+bool
+DbUtil::isConnected(){
+ if (m_connected == true)
+ {
+ assert(m_mysql);
+ return true;
}
+ return connect() == 0;
+}
- ndbout << "default_file: " << default_file.c_str() << endl;
- ndbout << "default_group: " << default_group.c_str() << endl;
+
+bool
+DbUtil::waitConnected(int timeout) {
+ timeout*= 10;
+ while(!isConnected()){
+ if (timeout-- == 0)
+ return false;
+ NdbSleep_MilliSleep(100);
+ }
+ return true;
}
-/* Destructor*/
+
+void
+DbUtil::disconnect(){
+ if (m_mysql != NULL){
+ if (m_free_mysql)
+ mysql_close(m_mysql);
+ m_mysql= NULL;
+ }
+ m_connected = false;
+}
+
+
+/* Destructor */
DbUtil::~DbUtil()
{
- this->databaseLogout();
+ disconnect();
}
/* Database Login */
@@ -62,18 +108,18 @@ DbUtil::databaseLogin(const char* system, const char* usr,
const char* password, unsigned int portIn,
const char* sockIn, bool transactional)
{
- if (!(mysql = mysql_init(NULL)))
+ if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB Login-> mysql_init() failed");
exit(DBU_FAILED);
}
- this->setUser(usr);
- this->setHost(system);
- this->setPassword(password);
- this->setPort(portIn);
- this->setSocket(sockIn);
+ setUser(usr);
+ setHost(system);
+ setPassword(password);
+ setPort(portIn);
+ setSocket(sockIn);
- if (!(mysql_real_connect(mysql,
+ if (!(mysql_real_connect(m_mysql,
m_host.c_str(),
m_user.c_str(),
m_pass.c_str(),
@@ -82,40 +128,40 @@ DbUtil::databaseLogin(const char* system, const char* usr,
m_socket.c_str(), 0)))
{
myerror("connection failed");
- mysql_close(mysql);
+ mysql_close(m_mysql);
exit(DBU_FAILED);
}
- mysql->reconnect = TRUE;
+ m_mysql->reconnect = TRUE;
/* set AUTOCOMMIT */
if(!transactional)
- mysql_autocommit(mysql, TRUE);
+ mysql_autocommit(m_mysql, TRUE);
else
- mysql_autocommit(mysql, FALSE);
+ mysql_autocommit(m_mysql, FALSE);
#ifdef DEBUG
printf("\n\tConnected to MySQL server version: %s (%lu)\n\n",
- mysql_get_server_info(mysql),
- (unsigned long) mysql_get_server_version(mysql));
+ mysql_get_server_info(m_mysql),
+ (unsigned long) mysql_get_server_version(m_mysql));
#endif
- this->selectDb();
+ selectDb();
}
/* Database Connect */
-int
+int
DbUtil::connect()
{
- if (!(mysql = mysql_init(NULL)))
+ if (!(m_mysql = mysql_init(NULL)))
{
myerror("DB connect-> mysql_init() failed");
return DBU_FAILED;
}
/* Load connection parameters file and group */
- if (mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, default_file.c_str()) ||
- mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, default_group.c_str()))
+ if (mysql_options(m_mysql, MYSQL_READ_DEFAULT_FILE, m_default_file.c_str()) ||
+ mysql_options(m_mysql, MYSQL_READ_DEFAULT_GROUP, m_default_group.c_str()))
{
myerror("DB Connect -> mysql_options failed");
return DBU_FAILED;
@@ -126,14 +172,14 @@ DbUtil::connect()
NOTE! user and password can be stored there as well
*/
- if (mysql_real_connect(mysql, NULL, "root","", m_dbname.c_str(),
+ if (mysql_real_connect(m_mysql, NULL, "root","", m_dbname.c_str(),
0, NULL, 0) == NULL)
{
myerror("connection failed");
- mysql_close(mysql);
+ mysql_close(m_mysql);
return DBU_FAILED;
}
- this->selectDb();
+ selectDb();
m_connected = true;
return DBU_OK;
}
@@ -141,14 +187,14 @@ DbUtil::connect()
/* Database Logout */
-void
+void
DbUtil::databaseLogout()
{
- if (mysql){
+ if (m_mysql){
#ifdef DEBUG
printf("\n\tClosing the MySQL database connection ...\n\n");
#endif
- mysql_close(mysql);
+ mysql_close(m_mysql);
}
}
@@ -181,28 +227,28 @@ DbUtil::mysqlCloseStmHandle(MYSQL_STMT *my_stmt)
/* Error Printing */
-void
+void
DbUtil::printError(const char *msg)
{
- if (this->getMysql() && mysql_errno(this->getMysql()))
+ if (m_mysql && mysql_errno(m_mysql))
{
- if (this->getMysql()->server_version)
- printf("\n [MySQL-%s]", this->getMysql()->server_version);
+ if (m_mysql->server_version)
+ printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
- printf("[%d] %s\n", this->getErrorNumber(), this->getError());
+ printf("[%d] %s\n", getErrorNumber(), getError());
}
else if (msg)
printf(" [MySQL] %s\n", msg);
}
-void
+void
DbUtil::printStError(MYSQL_STMT *stmt, const char *msg)
{
if (stmt && mysql_stmt_errno(stmt))
{
- if (this->getMysql() && this->getMysql()->server_version)
- printf("\n [MySQL-%s]", this->getMysql()->server_version);
+ if (m_mysql && m_mysql->server_version)
+ printf("\n [MySQL-%s]", m_mysql->server_version);
else
printf("\n [MySQL]");
@@ -215,19 +261,19 @@ DbUtil::printStError(MYSQL_STMT *stmt, const char *msg)
/* Select which database to use */
-int
+int
DbUtil::selectDb()
{
- if ((this->getDbName()) != NULL)
+ if ((getDbName()) != NULL)
{
- if(mysql_select_db(this->getMysql(), this->getDbName()))
+ if(mysql_select_db(m_mysql, this->getDbName()))
{
- this->printError("mysql_select_db failed");
+ printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
}
- this->printError("getDbName() == NULL");
+ printError("getDbName() == NULL");
return DBU_FAILED;
}
@@ -235,9 +281,9 @@ int
DbUtil::selectDb(const char * m_db)
{
{
- if(mysql_select_db(this->getMysql(), m_db))
+ if(mysql_select_db(m_mysql, m_db))
{
- this->printError("mysql_select_db failed");
+ printError("mysql_select_db failed");
return DBU_FAILED;
}
return DBU_OK;
@@ -249,89 +295,383 @@ DbUtil::createDb(BaseString& m_db)
{
BaseString stm;
{
- if(mysql_select_db(this->getMysql(), m_db.c_str()) == DBU_OK)
+ if(mysql_select_db(m_mysql, m_db.c_str()) == DBU_OK)
{
stm.assfmt("DROP DATABASE %s", m_db.c_str());
- if(this->doQuery(m_db.c_str()) == DBU_FAILED)
+ if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
}
stm.assfmt("CREATE DATABASE %s", m_db.c_str());
- if(this->doQuery(m_db.c_str()) == DBU_FAILED)
+ if(doQuery(m_db.c_str()) == DBU_FAILED)
return DBU_FAILED;
return DBU_OK;
}
}
-/* Run Simple Queries */
-int
-DbUtil::doQuery(BaseString& str)
+/* Count Table Rows */
+
+unsigned long
+DbUtil::selectCountTable(const char * table)
{
- if(mysql_query(this->getMysql(), str.c_str()))
- {
- this->printError(str.c_str());
- return DBU_FAILED;
+ BaseString query;
+ SqlResultSet result;
+
+ query.assfmt("select count(*) as count from %s", table);
+ if (!doQuery(query, result)) {
+ printError("select count(*) failed");
+ return -1;
}
- return DBU_OK;
+ return result.columnAsInt("count");
}
-int
-DbUtil::doQuery(const char * stm)
-{
- if(mysql_query(this->getMysql(), stm))
+
+/* Run Simple Queries */
+
+
+static bool is_int_type(enum_field_types type){
+ switch(type){
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_ENUM:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+
+bool
+DbUtil::runQuery(const char* sql,
+ const Properties& args,
+ SqlResultSet& rows){
+
+ rows.clear();
+ if (!isConnected())
+ return false;
+
+ g_debug << "runQuery: " << endl
+ << " sql: '" << sql << "'" << endl;
+
+
+ MYSQL_STMT *stmt= mysql_stmt_init(m_mysql);
+ if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
{
- this->printError(stm);
- return DBU_FAILED;
+ g_err << "Failed to prepare: " << mysql_error(m_mysql) << endl;
+ return false;
}
- return DBU_OK;
+
+ uint params= mysql_stmt_param_count(stmt);
+ MYSQL_BIND bind_param[params];
+ bzero(bind_param, sizeof(bind_param));
+
+ for(uint i= 0; i < mysql_stmt_param_count(stmt); i++)
+ {
+ BaseString name;
+ name.assfmt("%d", i);
+ // Parameters are named 0, 1, 2...
+ if (!args.contains(name.c_str()))
+ {
+ g_err << "param " << i << " missing" << endl;
+ assert(false);
+ }
+ PropertiesType t;
+ Uint32 val_i;
+ const char* val_s;
+ args.getTypeOf(name.c_str(), &t);
+ switch(t) {
+ case PropertiesType_Uint32:
+ args.get(name.c_str(), &val_i);
+ bind_param[i].buffer_type= MYSQL_TYPE_LONG;
+ bind_param[i].buffer= (char*)&val_i;
+ g_debug << " param" << name.c_str() << ": " << val_i << endl;
+ break;
+ case PropertiesType_char:
+ args.get(name.c_str(), &val_s);
+ bind_param[i].buffer_type= MYSQL_TYPE_STRING;
+ bind_param[i].buffer= (char*)val_s;
+ bind_param[i].buffer_length= strlen(val_s);
+ g_debug << " param" << name.c_str() << ": " << val_s << endl;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (mysql_stmt_bind_param(stmt, bind_param))
+ {
+ g_err << "Failed to bind param: " << mysql_error(m_mysql) << endl;
+ mysql_stmt_close(stmt);
+ return false;
+ }
+
+ if (mysql_stmt_execute(stmt))
+ {
+ g_err << "Failed to execute: " << mysql_error(m_mysql) << endl;
+ mysql_stmt_close(stmt);
+ return false;
+ }
+
+ /*
+ Update max_length, making it possible to know how big
+ buffers to allocate
+ */
+ my_bool one= 1;
+ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one);
+
+ if (mysql_stmt_store_result(stmt))
+ {
+ g_err << "Failed to store result: " << mysql_error(m_mysql) << endl;
+ mysql_stmt_close(stmt);
+ return false;
+ }
+
+ uint row= 0;
+ MYSQL_RES* res= mysql_stmt_result_metadata(stmt);
+ if (res != NULL)
+ {
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
+ uint num_fields= mysql_num_fields(res);
+ MYSQL_BIND bind_result[num_fields];
+ bzero(bind_result, sizeof(bind_result));
+
+ for (uint i= 0; i < num_fields; i++)
+ {
+ if (is_int_type(fields[i].type)){
+ bind_result[i].buffer_type= MYSQL_TYPE_LONG;
+ bind_result[i].buffer= malloc(sizeof(int));
+ }
+ else
+ {
+ uint max_length= fields[i].max_length + 1;
+ bind_result[i].buffer_type= MYSQL_TYPE_STRING;
+ bind_result[i].buffer= malloc(max_length);
+ bind_result[i].buffer_length= max_length;
+ }
+ }
+
+ if (mysql_stmt_bind_result(stmt, bind_result)){
+ g_err << "Failed to bind result: " << mysql_error(m_mysql) << endl;
+ mysql_stmt_close(stmt);
+ return false;
+ }
+
+ while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
+ {
+ Properties curr(true);
+ for (uint i= 0; i < num_fields; i++){
+ if (is_int_type(fields[i].type))
+ curr.put(fields[i].name, *(int*)bind_result[i].buffer);
+ else
+ curr.put(fields[i].name, (char*)bind_result[i].buffer);
+ }
+ rows.put("row", row++, &curr);
+ }
+
+ mysql_free_result(res);
+
+ for (uint i= 0; i < num_fields; i++)
+ free(bind_result[i].buffer);
+
+ }
+
+ // Save stats in result set
+ rows.put("rows", row);
+ rows.put("affected_rows", mysql_affected_rows(m_mysql));
+ rows.put("mysql_errno", mysql_errno(m_mysql));
+ rows.put("mysql_error", mysql_error(m_mysql));
+ rows.put("mysql_sqlstate", mysql_sqlstate(m_mysql));
+ rows.put("insert_id", mysql_insert_id(m_mysql));
+
+ mysql_stmt_close(stmt);
+ return true;
+}
+
+
+bool
+DbUtil::doQuery(const char* query){
+ const Properties args;
+ SqlResultSet result;
+ return doQuery(query, args, result);
+}
+
+
+bool
+DbUtil::doQuery(const char* query, SqlResultSet& result){
+ Properties args;
+ return doQuery(query, args, result);
+}
+
+
+bool
+DbUtil::doQuery(const char* query, const Properties& args,
+ SqlResultSet& result){
+ if (!runQuery(query, args, result))
+ return false;
+ result.get_row(0); // Load first row
+ return true;
+}
+
+
+bool
+DbUtil::doQuery(BaseString& str){
+ return doQuery(str.c_str());
}
+
+bool
+DbUtil::doQuery(BaseString& str, SqlResultSet& result){
+ return doQuery(str.c_str(), result);
+}
+
+
+bool
+DbUtil::doQuery(BaseString& str, const Properties& args,
+ SqlResultSet& result){
+ return doQuery(str.c_str(), args, result);
+}
+
+
/* Return MySQL Error String */
-const char *
+const char *
DbUtil::getError()
{
return mysql_error(this->getMysql());
}
-/* Retrun MySQL Error Number */
+/* Return MySQL Error Number */
-int
+int
DbUtil::getErrorNumber()
{
return mysql_errno(this->getMysql());
}
-/* Count Table Rows */
-
-unsigned long
-DbUtil::selectCountTable(const char * table)
-{
- unsigned long m_count = 0;
- BaseString m_query;
-
- m_query.assfmt("select count(*) from %s", table);
- if (mysql_query(this->getMysql(),m_query.c_str()) ||
- !(m_result=mysql_store_result(this->getMysql())))
- {
- this->printError("selectCountTable\n");
- return DBU_FAILED;
- }
- m_row = mysql_fetch_row(m_result);
- m_count = (ulong) strtoull(m_row[0], (char**) 0, 10);
- mysql_free_result(m_result);
-
- return m_count;
-}
-
/* DIE */
-void
+void
DbUtil::die(const char *file, int line, const char *expr)
{
printf("%s:%d: check failed: '%s'\n", file, line, expr);
abort();
}
+
+/* SqlResultSet */
+
+bool
+SqlResultSet::get_row(int row_num){
+ if(!get("row", row_num, &m_curr_row)){
+ return false;
+ }
+ return true;
+}
+
+
+bool
+SqlResultSet::next(void){
+ return get_row(++m_curr_row_num);
+}
+
+
+// Reset iterator
+void SqlResultSet::reset(void){
+ m_curr_row_num= -1;
+ m_curr_row= 0;
+}
+
+
+// Remove row from resultset
+void SqlResultSet::remove(){
+ BaseString row_name;
+ row_name.assfmt("row_%d", m_curr_row_num);
+ Properties::remove(row_name.c_str());
+}
+
+
+SqlResultSet::SqlResultSet(): m_curr_row(0), m_curr_row_num(-1){
+}
+
+
+SqlResultSet::~SqlResultSet(){
+}
+
+
+const char* SqlResultSet::column(const char* col_name){
+ const char* value;
+ if (!m_curr_row){
+ g_err << "ERROR: SqlResultSet::column("<< col_name << ")" << endl
+ << "There is no row loaded, call next() before "
+ << "acessing the column values" << endl;
+ assert(m_curr_row);
+ }
+ if (!m_curr_row->get(col_name, &value))
+ return NULL;
+ return value;
+}
+
+
+uint SqlResultSet::columnAsInt(const char* col_name){
+ uint value;
+ if (!m_curr_row){
+ g_err << "ERROR: SqlResultSet::columnAsInt("<< col_name << ")" << endl
+ << "There is no row loaded, call next() before "
+ << "acessing the column values" << endl;
+ assert(m_curr_row);
+ }
+ if (!m_curr_row->get(col_name, &value))
+ return (uint)-1;
+ return value;
+}
+
+
+uint SqlResultSet::insertId(){
+ return get_int("insert_id");
+}
+
+
+uint SqlResultSet::affectedRows(){
+ return get_int("affected_rows");
+}
+
+
+uint SqlResultSet::numRows(void){
+ return get_int("rows");
+}
+
+
+uint SqlResultSet::mysqlErrno(void){
+ return get_int("mysql_errno");
+}
+
+
+const char* SqlResultSet::mysqlError(void){
+ return get_string("mysql_error");
+}
+
+
+const char* SqlResultSet::mysqlSqlstate(void){
+ return get_string("mysql_sqlstate");
+}
+
+
+uint SqlResultSet::get_int(const char* name){
+ uint value;
+ get(name, &value);
+ return value;
+}
+
+
+const char* SqlResultSet::get_string(const char* name){
+ const char* value;
+ get(name, &value);
+ return value;
+}
+
/* EOF */