summaryrefslogtreecommitdiff
path: root/storage/ndb/test
diff options
context:
space:
mode:
authorunknown <tomas@whalegate.ndb.mysql.com>2008-01-23 14:42:58 +0100
committerunknown <tomas@whalegate.ndb.mysql.com>2008-01-23 14:42:58 +0100
commite69bf055ab62f4b6c57c31c51817e16a42cc48dc (patch)
tree2cf1f9a612f38c1ec9559cffdea68f44a53725ab /storage/ndb/test
parent20a7ea72eb4b5bdff9d57d33c1989e8cf5e5fc6a (diff)
parent78ac242f2bae276bf9cb72617e70d7ca7b9e829f (diff)
downloadmariadb-git-e69bf055ab62f4b6c57c31c51817e16a42cc48dc.tar.gz
Merge whalegate.ndb.mysql.com:/home/tomas/cge-5.1
into whalegate.ndb.mysql.com:/home/tomas/mysql-5.1-new-ndb-bj storage/ndb/src/kernel/blocks/ERROR_codes.txt: manual merge
Diffstat (limited to 'storage/ndb/test')
-rw-r--r--storage/ndb/test/include/AtrtClient.hpp56
-rwxr-xr-xstorage/ndb/test/include/DbUtil.hpp97
-rw-r--r--storage/ndb/test/ndbapi/Makefile.am9
-rw-r--r--storage/ndb/test/ndbapi/testBitfield.cpp408
-rw-r--r--storage/ndb/test/ndbapi/testNDBT.cpp173
-rw-r--r--storage/ndb/test/ndbapi/test_event.cpp61
-rw-r--r--storage/ndb/test/run-test/daily-basic-tests.txt4
-rw-r--r--storage/ndb/test/src/AtrtClient.cpp215
-rwxr-xr-xstorage/ndb/test/src/DbUtil.cpp546
-rw-r--r--storage/ndb/test/src/Makefile.am6
10 files changed, 1438 insertions, 137 deletions
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 <DbUtil.hpp>
+
+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 5ca5fca290c..d865c92f9a3 100755
--- a/storage/ndb/test/include/DbUtil.hpp
+++ b/storage/ndb/test/include/DbUtil.hpp
@@ -19,17 +19,11 @@
#ifndef DBUTIL_HPP
#define DBUTIL_HPP
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
+#include <NDBT.hpp>
+#include <BaseString.hpp>
+#include <Properties.hpp>
+#include <Vector.hpp>
#include <mysql.h>
-//include "rand.h"
-#include <stdlib.h>
-#include "BaseString.hpp"
-#include "NDBT.hpp"
//#define DEBUG
#define DIE_UNLESS(expr) \
@@ -52,8 +46,41 @@ if (r) \
DIE_UNLESS(r == 0);\
}
-#define DBU_TRUE 1
-#define DBU_FALSE 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
@@ -61,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,
@@ -79,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;
@@ -107,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);};
@@ -125,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 ad509dbbafe..81bb346417f 100644
--- a/storage/ndb/test/ndbapi/Makefile.am
+++ b/storage/ndb/test/ndbapi/Makefile.am
@@ -52,7 +52,9 @@ testBitfield \
DbCreate DbAsyncGenerator \
testSRBank \
test_event_merge \
-testIndexStat
+testIndexStat \
+testNDBT \
+NdbRepStress
EXTRA_PROGRAMS = \
test_event \
@@ -98,7 +100,10 @@ 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
DbAsyncGenerator_SOURCES = bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp
testSRBank_SOURCES = testSRBank.cpp
@@ -115,8 +120,10 @@ include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am
##testIndex_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
##testSystemRestart_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
##testTransactions_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel
+NdbRepStress_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/test/include -I$(top_srcdir)/include
testBackup_LDADD = $(LDADD) bank/libbank.a
testSRBank_LDADD = bank/libbank.a $(LDADD)
+NdbRepStress_LDADD = $(LDADD) $(top_builddir)/libmysql_r/libmysqlclient_r.la
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/storage/ndb/test/ndbapi/testBitfield.cpp b/storage/ndb/test/ndbapi/testBitfield.cpp
index 8ba8f3d92ef..41bb7b4622c 100644
--- a/storage/ndb/test/ndbapi/testBitfield.cpp
+++ b/storage/ndb/test/ndbapi/testBitfield.cpp
@@ -4,6 +4,8 @@
#include <NDBT.hpp>
#include <NdbApi.hpp>
#include <HugoTransactions.hpp>
+#include <Bitmask.hpp>
+#include <Vector.hpp>
static const char* _dbname = "TEST_DB";
static int g_loops = 7;
@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
static int node_restart(Ndb*, const NdbDictionary::Table* tab);
static int system_restart(Ndb*, const NdbDictionary::Table* tab);
+static int testBitmask();
int
main(int argc, char** argv){
@@ -49,6 +52,15 @@ main(int argc, char** argv){
ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
+ int res = NDBT_FAILED;
+
+ /* Run cluster-independent tests */
+ for (int i=0; i<(10*g_loops); i++)
+ {
+ if (NDBT_OK != (res= testBitmask()))
+ return NDBT_ProgramExit(res);
+ }
+
Ndb_cluster_connection con(opt_connect_str);
if(con.connect(12, 5, 1))
{
@@ -60,7 +72,6 @@ main(int argc, char** argv){
pNdb = new Ndb(&con, _dbname);
pNdb->init();
while (pNdb->waitUntilReady() != 0);
- int res = NDBT_FAILED;
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb)
do {
NdbDictionary::Table tab;
Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
- Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
Uint32 length = 4090;
- Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
BaseString name;
name.assfmt("TAB_%d", rand() & 65535);
tab.setName(name.c_str());
- for(int i = 0; i<cols && length > 2; i++)
+ for(Uint32 i = 0; i<cols && length > 2; i++)
{
NdbDictionary::Column col;
name.assfmt("COL_%d", i);
@@ -206,3 +215,394 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
{
return 0;
}
+
+/* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
+ * and were originally defined there.
+ * Set BITMASK_DEBUG to 1 to get more test debugging info.
+ */
+#define BITMASK_DEBUG 0
+
+static
+bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
+{
+ Uint32 sz32 = (len + 31) >> 5;
+ for(Uint32 i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
+ return false;
+ }
+ return true;
+}
+
+static
+void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
+{
+ printf("b'");
+ for(unsigned i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
+ printf("1");
+ else
+ printf("0");
+ if((i & 31) == 31)
+ printf(" ");
+ }
+}
+
+static int lrand()
+{
+ return rand();
+}
+
+static
+void rand(Uint32 dst[], Uint32 len)
+{
+ for(Uint32 i = 0; i<len; i++)
+ BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
+}
+
+static
+int checkNoTramplingGetSetField(const Uint32 totalTests)
+{
+ const Uint32 numWords= 67;
+ const Uint32 maxBitsToCopy= (numWords * 32);
+ Uint32 sourceBuf[numWords];
+ Uint32 targetBuf[numWords];
+
+ ndbout << "Testing : Bitmask NoTrampling\n";
+
+ memset(sourceBuf, 0x00, (numWords*4));
+
+ for (Uint32 test=0; test<totalTests; test++)
+ {
+ /* Always copy at least 1 bit */
+ Uint32 srcStart= rand() % (maxBitsToCopy -1);
+ Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
+
+ if (BITMASK_DEBUG)
+ ndbout << "Testing start %u, length %u \n"
+ << srcStart
+ << length;
+ // Set target to all ones.
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
+
+ // Check that there is no trampling
+ Uint32 firstUntrampledWord= (length + 31)/32;
+
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+ if (BITMASK_DEBUG)
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+
+ if (! (word < firstUntrampledWord) ?
+ (targetWord == 0) :
+ (targetWord == 0xffffffff))
+ {
+ ndbout << "Notrampling getField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << "\n";
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+ return -1;
+ }
+
+ }
+
+ /* Set target back to all ones. */
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
+
+ /* Check we've got all ones, with zeros only where expected */
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+
+ for (Uint32 bit=0; bit< 32; bit++)
+ {
+ Uint32 bitNum= (word << 5) + bit;
+ bool expectedValue= !((bitNum >= srcStart) &&
+ (bitNum < (srcStart + length)));
+ bool actualValue= (((targetWord >> bit) & 1) == 1);
+ if (BITMASK_DEBUG)
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+
+ if (actualValue != expectedValue)
+ {
+ ndbout << "Notrampling setField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << " bit " << bit << "\n";
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+ return -1;
+ }
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static
+int simple(int pos, int size)
+{
+ ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n";
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+ Uint32 sz32 = (size + pos + 32) >> 5;
+ const Uint32 sz = 4 * sz32;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ memset(src, 0x0, sz);
+ memset(dst, 0x0, sz);
+ memset(mask, 0xFF, sz);
+ rand(src, size);
+ BitmaskImpl::setField(sz32, mask, pos, size, src);
+ BitmaskImpl::getField(sz32, mask, pos, size, dst);
+ if (BITMASK_DEBUG)
+ {
+ printf("src: "); print(src, size+31); printf("\n");
+ printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
+ printf("dst: "); print(dst, size+31); printf("\n");
+ }
+ return (cmp(src, dst, size+31)?0 : -1);
+};
+
+struct Alloc
+{
+ Uint32 pos;
+ Uint32 size;
+ Vector<Uint32> data;
+};
+
+static
+int
+testRanges(Uint32 bitmask_size)
+{
+ Vector<Alloc> alloc_list;
+ bitmask_size = (bitmask_size + 31) & ~31;
+ Uint32 sz32 = (bitmask_size >> 5);
+ Vector<Uint32> alloc_mask;
+ Vector<Uint32> test_mask;
+
+ ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
+ Uint32 zero = 0;
+ alloc_mask.fill(sz32, zero);
+ test_mask.fill(sz32, zero);
+
+ /* Loop a number of times, setting and clearing bits in the mask
+ * and tracking the modifications in a separate structure.
+ * Check that both structures remain in sync
+ */
+ for(int i = 0; i<5000; i++)
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ Uint32 pos = lrand() % (bitmask_size - 1);
+ Uint32 free = 0;
+ if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
+ {
+ // Bit was allocated
+ // 1) Look up allocation
+ // 2) Check data
+ // 3) free it
+ size_t j;
+ Uint32 min, max;
+ for(j = 0; j<alloc_list.size(); j++)
+ {
+ min = alloc_list[j].pos;
+ max = min + alloc_list[j].size;
+ if(pos >= min && pos < max)
+ {
+ break;
+ }
+ }
+ if (! ((pos >= min) && (pos < max)))
+ {
+ printf("Failed with pos %u, min %u, max %u\n",
+ pos, min, max);
+ return -1;
+ }
+ BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
+ tmp.getBase());
+ if(BITMASK_DEBUG)
+ {
+ printf("freeing [ %d %d ]", min, max);
+ printf("- mask: ");
+ print(tmp.getBase(), max - min);
+
+ printf(" save: ");
+ size_t k;
+ Alloc& a = alloc_list[j];
+ for(k = 0; k<a.data.size(); k++)
+ printf("%.8x ", a.data[k]);
+ printf("\n");
+ }
+ if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
+ {
+ return -1;
+ }
+ while(min < max)
+ BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
+ alloc_list.erase(j);
+ }
+ else
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ // Bit was free
+ // 1) Check how much space is avaiable
+ // 2) Create new allocation of lrandom size
+ // 3) Fill data with lrandom data
+ // 4) Update alloc mask
+ while(pos+free < bitmask_size &&
+ !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
+ free++;
+
+ Uint32 sz =
+ (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
+ sz = sz ? sz : 1;
+ sz = pos + sz == bitmask_size ? sz - 1 : sz;
+ Alloc a;
+ a.pos = pos;
+ a.size = sz;
+ a.data.fill(((sz+31)>> 5)-1, zero);
+ if(BITMASK_DEBUG)
+ printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
+ for(size_t j = 0; j<sz; j++)
+ {
+ BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
+ if((lrand() % 1000) > 500)
+ BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
+ }
+ if(BITMASK_DEBUG)
+ {
+ printf("- mask: ");
+ print(a.data.getBase(), sz);
+ printf("\n");
+ }
+ BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
+ a.data.getBase());
+ alloc_list.push_back(a);
+ }
+ }
+
+#define NDB_BM_SUPPORT_RANGE
+#ifdef NDB_BM_SUPPORT_RANGE
+ for(Uint32 i = 0; i<1000; i++)
+ {
+ Uint32 sz32 = 10+rand() % 100;
+ Uint32 zero = 0;
+ Vector<Uint32> map;
+ map.fill(sz32, zero);
+
+ Uint32 sz = 32 * sz32;
+ Uint32 start = (rand() % sz);
+ Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
+
+ Vector<Uint32> check;
+ check.fill(sz32, zero);
+
+ /* Verify range setting method works correctly */
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::set(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::set_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+
+ map.clear();
+ check.clear();
+
+ /* Verify range clearing method works correctly */
+ Uint32 one = ~(Uint32)0;
+ map.fill(sz32, one);
+ check.fill(sz32, one);
+
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::clear(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static
+int
+testBitmask()
+{
+ /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
+ int res= 0;
+
+ if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
+ return res;
+
+ if ((res= simple(rand() % 33, // position
+ (rand() % 63)+1) // size
+ ) != 0)
+ return res;
+
+ if ((res= testRanges(1+(rand() % 1000) // bitmask size
+ )) != 0)
+ return res;
+
+ return 0;
+}
+
+template class Vector<Alloc>;
+template class Vector<Uint32>;
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 <NDBT.hpp>
+#include <NDBT_Test.hpp>
+#include <DbUtil.hpp>
+#include <AtrtClient.hpp>
+
+
+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/ndbapi/test_event.cpp b/storage/ndb/test/ndbapi/test_event.cpp
index 18825d734a4..a7504166065 100644
--- a/storage/ndb/test/ndbapi/test_event.cpp
+++ b/storage/ndb/test/ndbapi/test_event.cpp
@@ -1838,6 +1838,61 @@ runBug31701(NDBT_Context* ctx, NDBT_Step* step)
return NDBT_OK;
}
+int
+runBug33793(NDBT_Context* ctx, NDBT_Step* step)
+{
+ int result = NDBT_OK;
+ int loops = ctx->getNumLoops();
+
+ NdbRestarter restarter;
+
+ if (restarter.getNumDbNodes() < 2){
+ ctx->stopTest();
+ return NDBT_OK;
+ }
+ // This should really wait for applier to start...10s is likely enough
+ NdbSleep_SecSleep(10);
+
+ while (loops-- && ctx->isTestStopped() == false)
+ {
+ int nodeId = restarter.getDbNodeId(rand() % restarter.getNumDbNodes());
+ int nodecount = 0;
+ int nodes[255];
+ printf("nodeid: %u : victims: ", nodeId);
+ for (int i = 0; i<restarter.getNumDbNodes(); i++)
+ {
+ int id = restarter.getDbNodeId(i);
+ if (id == nodeId)
+ continue;
+
+ if (restarter.getNodeGroup(id) == restarter.getNodeGroup(nodeId))
+ {
+ nodes[nodecount++] = id;
+ printf("%u ", id);
+ int val2[] = { DumpStateOrd::CmvmiSetRestartOnErrorInsert, 1 };
+ if (restarter.dumpStateOneNode(id, val2, 2))
+ return NDBT_FAILED;
+ }
+ }
+ printf("\n"); fflush(stdout);
+
+ restarter.insertErrorInNode(nodeId, 13034);
+ if (restarter.waitNodesNoStart(nodes, nodecount))
+ return NDBT_FAILED;
+
+ if (restarter.startNodes(nodes, nodecount))
+ return NDBT_FAILED;
+
+ if (restarter.waitClusterStarted())
+ return NDBT_FAILED;
+ }
+
+ ctx->stopTest();
+ return NDBT_OK;
+}
+
+
+
NDBT_TESTSUITE(test_event);
TESTCASE("BasicEventOperation",
"Verify that we can listen to Events"
@@ -1975,6 +2030,12 @@ TESTCASE("Bug31701", ""){
FINALIZER(runDropEvent);
FINALIZER(runDropShadowTable);
}
+TESTCASE("Bug33793", ""){
+ INITIALIZER(runCreateEvent);
+ STEP(runEventListenerUntilStopped);
+ STEP(runBug33793);
+ FINALIZER(runDropEvent);
+}
NDBT_TESTSUITE_END(test_event);
int main(int argc, const char** argv){
diff --git a/storage/ndb/test/run-test/daily-basic-tests.txt b/storage/ndb/test/run-test/daily-basic-tests.txt
index 37db5e01dd6..1aee1555f00 100644
--- a/storage/ndb/test/run-test/daily-basic-tests.txt
+++ b/storage/ndb/test/run-test/daily-basic-tests.txt
@@ -1046,3 +1046,7 @@ max-time: 300
cmd: testSystemRestart
args: -n Bug22696 T1
+max-time: 300
+cmd: test_event
+args: -n Bug33793 T1
+
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 <AtrtClient.hpp>
+#include <NDBT_Output.hpp>
+#include <NdbSleep.h>
+
+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 1df4f8f745e..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 = DBU_TRUE;
+ m_mysql->reconnect = TRUE;
/* set AUTOCOMMIT */
if(!transactional)
- mysql_autocommit(mysql, DBU_TRUE);
+ mysql_autocommit(m_mysql, TRUE);
else
- mysql_autocommit(mysql, DBU_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 aa486108235..1e4f30c3f39 100644
--- a/storage/ndb/test/src/Makefile.am
+++ b/storage/ndb/test/src/Makefile.am
@@ -23,10 +23,10 @@ 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 \
- CpcClient.cpp NdbMixRestarter.cpp NDBT_Thread.cpp dbutil.cpp
+ 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
+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
include $(top_srcdir)/storage/ndb/config/common.mk.am
include $(top_srcdir)/storage/ndb/config/type_ndbapitest.mk.am