From 4789e3f60669904a3032b59c6fb25f7ba6966bfe Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 18 Jan 2008 22:55:02 +0100 Subject: Add SqlResultSet storage/ndb/test/include/DbUtil.hpp: Add support for SqlResultSet storage/ndb/test/ndbapi/Makefile.am: Add testNDBT storage/ndb/test/src/DbUtil.cpp: Add support for SqlResultSet storage/ndb/test/src/Makefile.am: Build AtrtClient storage/ndb/test/include/AtrtClient.hpp: New BitKeeper file ``storage/ndb/test/include/AtrtClient.hpp'' storage/ndb/test/ndbapi/testNDBT.cpp: New BitKeeper file ``storage/ndb/test/ndbapi/testNDBT.cpp'' storage/ndb/test/src/AtrtClient.cpp: New BitKeeper file ``storage/ndb/test/src/AtrtClient.cpp'' --- storage/ndb/test/include/AtrtClient.hpp | 56 ++++ storage/ndb/test/include/DbUtil.hpp | 92 ++++-- storage/ndb/test/ndbapi/Makefile.am | 3 + storage/ndb/test/ndbapi/testNDBT.cpp | 173 ++++++++++ storage/ndb/test/src/AtrtClient.cpp | 215 +++++++++++++ storage/ndb/test/src/DbUtil.cpp | 546 ++++++++++++++++++++++++++------ storage/ndb/test/src/Makefile.am | 2 +- 7 files changed, 962 insertions(+), 125 deletions(-) create mode 100644 storage/ndb/test/include/AtrtClient.hpp create mode 100644 storage/ndb/test/ndbapi/testNDBT.cpp create mode 100644 storage/ndb/test/src/AtrtClient.cpp (limited to 'storage/ndb/test') diff --git a/storage/ndb/test/include/AtrtClient.hpp b/storage/ndb/test/include/AtrtClient.hpp new file mode 100644 index 00000000000..5728aca2500 --- /dev/null +++ b/storage/ndb/test/include/AtrtClient.hpp @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef ATRT_CLIENT_HPP +#define ATRT_CLIENT_HPP + +#include + +class AtrtClient: public DbUtil { +public: + + enum AtrtCommandType { + ATCT_CHANGE_VERSION= 1, + ATCT_RESET_PROC= 2 + }; + + AtrtClient(const char* _user= "root", + const char* _password= "", + const char* _suffix= ".1.atrt"); + AtrtClient(MYSQL*); + ~AtrtClient(); + + + // Command functions + bool changeVersion(int process_id, const char* process_args); + bool resetProc(int process_id); + + // Query functions + bool getConnectString(int cluster_id, SqlResultSet& result); + bool getClusters(SqlResultSet& result); + bool getMgmds(int cluster_id, SqlResultSet& result); + bool getNdbds(int cluster_id, SqlResultSet& result); + +private: + int writeCommand(AtrtCommandType _type, + const Properties& args); + bool readCommand(uint command_id, + SqlResultSet& result); + + bool doCommand(AtrtCommandType _type, + const Properties& args); +}; + +#endif diff --git a/storage/ndb/test/include/DbUtil.hpp b/storage/ndb/test/include/DbUtil.hpp index a1172205ff9..d865c92f9a3 100755 --- a/storage/ndb/test/include/DbUtil.hpp +++ b/storage/ndb/test/include/DbUtil.hpp @@ -19,14 +19,11 @@ #ifndef DBUTIL_HPP #define DBUTIL_HPP -#include -#include -#include +#include +#include +#include +#include #include -//include "rand.h" -#include -#include "BaseString.hpp" -#include "NDBT.hpp" //#define DEBUG #define DIE_UNLESS(expr) \ @@ -49,6 +46,41 @@ if (r) \ DIE_UNLESS(r == 0);\ } + +class SqlResultSet : public Properties { +public: + + // Get row with number + bool get_row(int row_num); + // Load next row + bool next(void); + // Reset iterator + void reset(void); + // Remove current row from resultset + void remove(); + + SqlResultSet(); + ~SqlResultSet(); + + const char* column(const char* col_name); + uint columnAsInt(const char* col_name); + + uint insertId(); + uint affectedRows(); + uint numRows(void); + uint mysqlErrno(); + const char* mysqlError(); + const char* mysqlSqlstate(); + +private: + uint get_int(const char* name); + const char* get_string(const char* name); + + const Properties* m_curr_row; + uint m_curr_row_num; +}; + + #define DBU_FAILED 1 #define DBU_OK 0 @@ -56,11 +88,23 @@ class DbUtil { public: - /* Deprecated, see DbUtil(dbname, suffix) */ - DbUtil(const char * databaseName); - DbUtil(const char* dbname, const char* suffix = NULL); + DbUtil(MYSQL* mysql); + DbUtil(const char* dbname = "mysql", + const char* user = "root", + const char* pass = "", + const char* suffix = NULL); ~DbUtil(); + bool doQuery(const char* query); + bool doQuery(const char* query, SqlResultSet& result); + bool doQuery(const char* query, const Properties& args, SqlResultSet& result); + + bool doQuery(BaseString& str); + bool doQuery(BaseString& str, SqlResultSet& result); + bool doQuery(BaseString& str, const Properties& args, SqlResultSet& result); + + bool waitConnected(int timeout); + /* Deprecated, see connect() */ void databaseLogin(const char * system, const char * usr, @@ -74,25 +118,35 @@ public: const char * getPassword(){return m_pass.c_str();}; const char * getHost() {return m_host.c_str();}; const char * getSocket() {return m_socket.c_str();}; - const char * getServerType(){return mysql_get_server_info(mysql);}; + const char * getServerType(){return mysql_get_server_info(m_mysql);}; const char * getError(); - MYSQL * getMysql(){return mysql;}; + MYSQL * getMysql(){return m_mysql;}; MYSQL_STMT * STDCALL mysqlSimplePrepare(const char *query); void databaseLogout(); void mysqlCloseStmHandle(MYSQL_STMT *my_stmt); int connect(); + void disconnect(); int selectDb(); int selectDb(const char *); int createDb(BaseString&); - int doQuery(BaseString&); - int doQuery(const char *); int getErrorNumber(); unsigned long selectCountTable(const char * table); +protected: + + bool runQuery(const char* query, + const Properties& args, + SqlResultSet& rows); + + bool isConnected(); + + MYSQL * m_mysql; + bool m_free_mysql; /* Don't free mysql* if allocated elsewhere */ + private: bool m_connected; @@ -102,15 +156,11 @@ private: BaseString m_pass; // MySQL User Password BaseString m_dbname; // Database to use BaseString m_socket; // MySQL Server Unix Socket - BaseString default_file; - BaseString default_group; + BaseString m_default_file; + BaseString m_default_group; unsigned int m_port; // MySQL Server port - MYSQL * mysql; - MYSQL_RES * m_result; - MYSQL_ROW m_row; - void setDbName(const char * name){m_dbname.assign(name);}; void setUser(const char * user_name){m_user.assign(user_name);}; void setPassword(const char * password){m_pass.assign(password);}; @@ -120,7 +170,7 @@ private: void printError(const char *msg); void printStError(MYSQL_STMT *stmt, const char *msg); void die(const char *file, int line, const char *expr); // stop program - + }; #endif diff --git a/storage/ndb/test/ndbapi/Makefile.am b/storage/ndb/test/ndbapi/Makefile.am index 9f83b061403..81bb346417f 100644 --- a/storage/ndb/test/ndbapi/Makefile.am +++ b/storage/ndb/test/ndbapi/Makefile.am @@ -53,6 +53,7 @@ DbCreate DbAsyncGenerator \ testSRBank \ test_event_merge \ testIndexStat \ +testNDBT \ NdbRepStress EXTRA_PROGRAMS = \ @@ -99,6 +100,8 @@ ndbapi_slow_select_SOURCES = slow_select.cpp testReadPerf_SOURCES = testReadPerf.cpp testLcp_SOURCES = testLcp.cpp testPartitioning_SOURCES = testPartitioning.cpp +testNDBT_SOURCES = testNDBT.cpp +testNDBT_LDADD = $(LDADD) $(top_srcdir)/libmysql_r/libmysqlclient_r.la testBitfield_SOURCES = testBitfield.cpp NdbRepStress_SOURCES = acrt/NdbRepStress.cpp DbCreate_SOURCES = bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp diff --git a/storage/ndb/test/ndbapi/testNDBT.cpp b/storage/ndb/test/ndbapi/testNDBT.cpp new file mode 100644 index 00000000000..9c911b9a9d9 --- /dev/null +++ b/storage/ndb/test/ndbapi/testNDBT.cpp @@ -0,0 +1,173 @@ +/* Copyright (C) 2003 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include + + +int runTestAtrtClient(NDBT_Context* ctx, NDBT_Step* step){ + AtrtClient atrt; + + SqlResultSet clusters; + if (!atrt.getClusters(clusters)) + return NDBT_FAILED; + + int i= 0; + while(clusters.next()) + { + ndbout << clusters.column("name") << endl; + if (i++ == 1){ + ndbout << "removing: " << clusters.column("name") << endl; + clusters.remove(); + } + } + + clusters.reset(); + while(clusters.next()) + { + ndbout << clusters.column("name") << endl; + } + + return NDBT_OK; +} + + +int runTestDbUtil(NDBT_Context* ctx, NDBT_Step* step){ + DbUtil sql; + + { + // Select all rows from mysql.user + SqlResultSet result; + if (!sql.doQuery("SELECT * FROM mysql.user", result)) + return NDBT_FAILED; + // result.print(); + + while(result.next()) + { + ndbout << result.column("host") << ", " + << result.column("uSer") << ", " + << result.columnAsInt("max_updates") << ", " + << endl; + } + + result.reset(); + while(result.next()) + { + ndbout << result.column("host") << endl; + } + } + + { + // No column name, query should fail + Properties args; + SqlResultSet result; + if (sql.doQuery("SELECT * FROM mysql.user WHERE name=?", args, result)) + return NDBT_FAILED; + result.print(); + } + + { + // Select nonexisiting rows from mysql.user + Properties args; + SqlResultSet result; + args.put("0", "no_such_host"); + if (!sql.doQuery("SELECT * FROM mysql.user WHERE host=?", args, result)) + return NDBT_FAILED; + ndbout << "no rows" << endl; + result.print(); + + // Change args to an find one row + args.clear(); + args.put("0", "localhost"); + if (!sql.doQuery("SELECT host, user FROM mysql.user WHERE host=?", + args, result)) + return NDBT_FAILED; + result.print(); + } + + { + if (!sql.doQuery("CREATE TABLE sql_client_test (a int, b varchar(255))")) + return NDBT_FAILED; + + if (!sql.doQuery("INSERT INTO sql_client_test VALUES(1, 'hello'), (2, 'bye')")) + return NDBT_FAILED; + + // Select all rows from sql_client_test + SqlResultSet result; + if (!sql.doQuery("SELECT * FROM sql_client_test", result)) + return NDBT_FAILED; + // result.print(); + + while(result.next()) + { + } + + // Select second row from sql_client_test + Properties args; + args.put("0", 2); + if (!sql.doQuery("SELECT * FROM sql_client_test WHERE a=?", args,result)) + return NDBT_FAILED; + result.print(); + + result.reset(); + while(result.next()) + { + ndbout << "a: " << result.columnAsInt("a") << endl; + ndbout << "b: " << result.column("b") << endl; + if (result.columnAsInt("a") != 2){ + ndbout << "hepp1" << endl; + return NDBT_FAILED; + } + + if (strcmp(result.column("b"), "bye")){ + ndbout << "hepp2" << endl; + return NDBT_FAILED; + } + + } + + if (sql.selectCountTable("sql_client_test") != 2) + { + ndbout << "Got wrong count" << endl; + return NDBT_FAILED; + } + + + if (!sql.doQuery("DROP TABLE sql_client_test")) + return NDBT_FAILED; + + } + + return NDBT_OK; +} + +NDBT_TESTSUITE(testNDBT); +TESTCASE("AtrtClient", + "Test AtrtClient class"){ + INITIALIZER(runTestAtrtClient); +} +TESTCASE("DbUtil", + "Test DbUtil class"){ + INITIALIZER(runTestDbUtil); +} +NDBT_TESTSUITE_END(testNDBT); + +int main(int argc, const char** argv){ + ndb_init(); + return testNDBT.execute(argc, argv); +} + diff --git a/storage/ndb/test/src/AtrtClient.cpp b/storage/ndb/test/src/AtrtClient.cpp new file mode 100644 index 00000000000..5183242f841 --- /dev/null +++ b/storage/ndb/test/src/AtrtClient.cpp @@ -0,0 +1,215 @@ +/* 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 + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include + +AtrtClient::AtrtClient(const char* _user, + const char* _password, + const char* _group_suffix) + : DbUtil(_user, _password, _group_suffix) +{ +} + + +AtrtClient::AtrtClient(MYSQL* mysql) + : DbUtil(mysql) +{ +} + + +AtrtClient::~AtrtClient(){ +} + + +int +AtrtClient::writeCommand(AtrtCommandType _type, + const Properties& args){ + if (!isConnected()) + return false; + + BaseString sql; + sql.assfmt("INSERT command ( "); + + const char* name; + { + Properties::Iterator iter(&args); + while((name= iter.next())){ + sql.appfmt("%s, ", name); + } + } + + sql.appfmt(" state, cmd) VALUES ("); + + { + Properties::Iterator iter(&args); + while((name= iter.next())){ + PropertiesType t; + Uint32 val_i; + BaseString val_s; + args.getTypeOf(name, &t); + switch(t) { + case PropertiesType_Uint32: + args.get(name, &val_i); + sql.appfmt("%d, ", val_i); + break; + case PropertiesType_char: + args.get(name, val_s); + sql.appfmt("'%s', ", val_s.c_str()); + break; + default: + assert(false); + break; + } + } + } + + sql.appfmt("'new', %d)", _type); + if (!doQuery(sql)){ + return -1; + } + + return mysql_insert_id(m_mysql); +} + + +bool +AtrtClient::readCommand(uint command_id, + SqlResultSet& result){ + Properties args; + args.put("0", command_id); + return runQuery("SELECT * FROM command WHERE id = ?", + args, + result); +} + + +bool +AtrtClient::doCommand(AtrtCommandType type, + const Properties& args){ + + int running_timeout= 10; + int total_timeout= 120; + int commandId= writeCommand(type, + args); + if (commandId == -1){ + g_err << "Failed to write command" << endl; + return false; + } + + while (true){ + + SqlResultSet result; + if (!readCommand(commandId, result)) + { + result.print(); + g_err << "Failed to read command "<< commandId << endl; + return false; + } + + // Get first row + result.next(); + + // Check if command has completed + BaseString state(result.column("state")); + if (state == "done") { + return true; + } + + if (state == "new"){ + if (!running_timeout--){ + g_err << "Timeout while waiting for command " + << commandId << " to start run" << endl; + return false; + } + } + else if (!total_timeout--){ + g_err << "Timeout while waiting for result of command " + << commandId << endl; + return false; + } + + + NdbSleep_SecSleep(1); + } + + return false; +} + + +bool +AtrtClient::changeVersion(int process_id, + const char* process_args){ + Properties args; + args.put("process_id", process_id); + args.put("process_args", process_args); + return doCommand(ATCT_CHANGE_VERSION, args); +} + + +bool +AtrtClient::resetProc(int process_id){ + Properties args; + args.put("process_id", process_id); + return doCommand(ATCT_RESET_PROC, args); +} + + +bool +AtrtClient::getConnectString(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return doQuery("SELECT value as connectstring " \ + "FROM cluster c, process p, host h, options o " \ + "WHERE c.id=p.cluster_id AND p.host_id=h.id AND " \ + "p.id=o.process_id AND c.id=? AND " \ + "o.name='--ndb-connectstring=' AND type='ndb_mgmd'", + args, + result); +} + + +bool +AtrtClient::getClusters(SqlResultSet& result){ + Properties args; + return runQuery("SELECT id, name FROM cluster WHERE name != '.atrt'", + args, + result); +} + + +bool +AtrtClient::getMgmds(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndb_mgmd'", + args, + result); +} + +bool +AtrtClient::getNdbds(int cluster_id, SqlResultSet& result){ + Properties args; + args.put("0", cluster_id); + return runQuery("SELECT * FROM process WHERE cluster_id=? and type='ndbd'", + args, + result); +} + + + + + 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 -/* 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 */ diff --git a/storage/ndb/test/src/Makefile.am b/storage/ndb/test/src/Makefile.am index 8cbe83dfbcf..1e4f30c3f39 100644 --- a/storage/ndb/test/src/Makefile.am +++ b/storage/ndb/test/src/Makefile.am @@ -23,7 +23,7 @@ libNDBT_a_SOURCES = \ HugoAsynchTransactions.cpp UtilTransactions.cpp \ NdbRestarter.cpp NdbRestarts.cpp NDBT_Output.cpp \ NdbBackup.cpp NdbConfig.cpp NdbGrep.cpp NDBT_Table.cpp \ - NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c \ + NdbSchemaCon.cpp NdbSchemaOp.cpp getarg.c AtrtClient.cpp \ CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp DbUtil.cpp INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/common/mgmcommon -I$(top_srcdir)/storage/ndb/include/mgmcommon -I$(top_srcdir)/storage/ndb/include/kernel -I$(top_srcdir)/storage/ndb/src/mgmapi -I$(top_srcdir)/include -- cgit v1.2.1