testodbcdriver.cpp
来自「MySQL数据库开发源码 值得一看哦」· C++ 代码 · 共 2,237 行 · 第 1/5 页
CPP
2,237 行
/* 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; either version 2 of the License, or (at your option) any later version. 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 *//* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either version 2 of the License, or (at your option) any later version. 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 *//* * testOdbcDriver * * Test of ODBC and SQL using a fixed set of tables. */#include <ndb_global.h>#undef test#include <ndb_version.h>#include <kernel/ndb_limits.h>#include <Bitmask.hpp>#include <kernel/AttributeList.hpp>#ifdef ndbODBC#include <NdbApi.hpp>#endif#include <sqlext.h>#undef BOOL#include <NdbMain.h>#include <NdbOut.hpp>#include <NdbThread.h>#include <NdbMutex.h>#include <NdbCondition.h>#include <NdbTick.h>#include <NdbSleep.h>#ifdef ndbODBC#include <NdbTest.hpp>#else#define NDBT_OK 0#define NDBT_FAILED 1#define NDBT_WRONGARGS 2static intNDBT_ProgramExit(int rcode){ const char* rtext = "Unknown"; switch (rcode) { case NDBT_OK: rtext = "OK"; break; case NDBT_FAILED: rtext = "Failed"; break; case NDBT_WRONGARGS: rtext = "Wrong arguments"; break; }; ndbout_c("\nNDBT_ProgramExit: %d - %s\n", rcode, rtext); return rcode;}#endif#ifdef DMALLOC#include <dmalloc.h>#endif#define arraySize(x) (sizeof(x)/sizeof(x[0]))#define SQL_ATTR_NDB_TUPLES_FETCHED 66601// options#define MAX_THR 128 // max threadsstruct Opt { const char* m_name[100]; unsigned m_namecnt; bool m_core; unsigned m_depth; const char* m_dsn; unsigned m_errs; const char* m_fragtype; unsigned m_frob; const char* m_home; unsigned m_loop; bool m_nogetd; bool m_noputd; bool m_nosort; unsigned m_scale; bool m_serial; const char* m_skip[100]; unsigned m_skipcnt; unsigned m_subloop; const char* m_table; unsigned m_threads; unsigned m_trace; unsigned m_v; Opt() : m_namecnt(0), m_core(false), m_depth(5), m_dsn("NDB"), m_errs(0), m_fragtype(0), m_frob(0), m_home(0), m_loop(1), m_nogetd(false), m_noputd(false), m_nosort(false), m_scale(100), m_serial(false), m_skipcnt(0), m_subloop(1), m_table(0), m_threads(1), m_trace(0), m_v(1) { for (unsigned i = 0; i < arraySize(m_name); i++) m_name[i] = 0; for (unsigned i = 0; i < arraySize(m_skip); i++) m_skip[i] = 0; }};static Opt opt;static void listCases();static void listTables();static void printusage(){ Opt d; ndbout << "usage: testOdbcDriver [options]" << endl << "-case name run only named tests (substring match - can be repeated)" << endl << "-core dump core on failure" << endl << "-depth N join depth - default " << d.m_depth << endl << "-dsn string data source name - default " << d.m_dsn << endl << "-errs N allow N errors before quitting - default " << d.m_errs << endl << "-fragtype t fragment type single/small/medium/large" << d.m_errs << endl << "-frob X case-dependent tweak (number)" << endl << "-home dir set NDB_HOME (contains Ndb.cfg)" << endl << "-loop N loop N times (0 = forever) - default " << d.m_loop << endl << "-nogetd do not use SQLGetData - default " << d.m_nogetd << endl << "-noputd do not use SQLPutData - default " << d.m_noputd << endl << "-nosort no order-by in verify scan (checks non-Pk values only)" << endl << "-scale N row count etc - default " << d.m_scale << endl << "-serial run multi-threaded test cases one at a time" << endl << "-skip name skip named tests (substring match - can be repeated)" << endl << "-subloop N loop count per case (same threads) - default " << d.m_subloop << endl << "-table T do only table T (table name on built-in list)" << endl << "-threads N number of threads (max " << MAX_THR << ") - default " << d.m_threads << endl << "-trace N trace in NDB ODBC driver - default " << d.m_trace << endl << "-v N verbosity - default " << d.m_v << endl ; listCases(); listTables();}static voidfatal(const char* fmt, ...){ va_list ap; char buf[200]; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); ndbout << buf << endl; if (opt.m_errs != 0) { opt.m_errs--; return; } if (opt.m_core) abort(); NDBT_ProgramExit(NDBT_FAILED); exit(1);}static voidcleanprint(const char* s, unsigned n){ for (unsigned i = 0; i < n; i++) { char b[10]; if (0x20 < s[i] && s[i] <= 0x7e) sprintf(b, "%c", s[i]); else sprintf(b, "\\%02x", (unsigned)s[i]); ndbout << b; }}// global mutexstatic NdbMutex my_mutex = NDB_MUTEX_INITIALIZER;static void lock_mutex() { NdbMutex_Lock(&my_mutex); }static void unlock_mutex() { NdbMutex_Unlock(&my_mutex); }// semaphore zeroed before each call to a test routinestatic unsigned my_sema = 0;// print mutexstatic NdbMutex out_mutex = NDB_MUTEX_INITIALIZER;static NdbOut& lock(NdbOut& out) { NdbMutex_Lock(&out_mutex); return out; }static NdbOut& unlock(NdbOut& out) { NdbMutex_Unlock(&out_mutex); return out; }static unsignedurandom(unsigned n){ assert(n != 0); unsigned i = random(); return i % n;}// test casesstruct Test;struct Case { enum Mode { Single = 1, // single thread Serial = 2, // all threads but one at a time Thread = 3 // all threads in parallel }; const char* m_name; void (*m_func)(Test& test); Mode m_mode; unsigned m_stuff; const char* m_desc; Case(const char* name, void (*func)(Test& test), Mode mode, unsigned stuff, const char* desc) : m_name(name), m_func(func), m_mode(mode), m_stuff(stuff), m_desc(desc) { } const char* modename() const { const char* s = "?"; if (m_mode == Case::Single) return "Single"; if (m_mode == Case::Serial) return "Serial"; if (m_mode == Case::Thread) return "Thread"; return "?"; } bool matchcase() const { if (opt.m_namecnt == 0) return ! skipcase(); for (unsigned i = 0; i < opt.m_namecnt; i++) { if (strstr(m_name, opt.m_name[i]) != 0) return ! skipcase(); } return false; }private: bool skipcase() const { for (unsigned i = 0; i < opt.m_skipcnt; i++) { if (strstr(m_name, opt.m_skip[i]) != 0) return true; } return false; }};// calculate valuesstruct Calc { enum { m_mul = 1000000 }; unsigned m_no; unsigned m_base; unsigned m_salt; // modifies non-PK values bool m_const; // base non-PK values on PK of row 0 Calc(unsigned no) : m_no(no), m_salt(0), m_const(false) { m_base = m_no * m_mul; } void calcPk(unsigned rownum, char* v, unsigned n) const { char b[10]; sprintf(b, "%08x", m_base + rownum); for (unsigned i = 0; i < n; i++) { char c = i < n - 1 ? b[i % 8] : 0; v[i] = c; } } void calcPk(unsigned rownum, long* v) const { *v = m_base + rownum; } void hashPk(unsigned* hash, const char* v, unsigned n) const { for (unsigned i = 0; i < n; i++) { *hash ^= (v[i] << i); } } void hashPk(unsigned* hash, long v) const { *hash ^= v; } void calcNk(unsigned hash, char* v, unsigned n, SQLINTEGER* ind, bool null) const { unsigned m = hash % n; for (unsigned i = 0; i < n; i++) { char c = i < m ? 'a' + (hash + i) % ('z' - 'a' + 1) : i < n - 1 ? ' ' : 0; v[i] = c; } *ind = null && hash % 9 == 0 ? SQL_NULL_DATA : SQL_NTS; } void calcNk(unsigned hash, long* v, SQLINTEGER* ind, bool null) const { *v = long(hash); *ind = null && hash % 7 == 0 ? SQL_NULL_DATA : 0; } void calcNk(unsigned hash, double* v, SQLINTEGER* ind, bool null) const { *v = long(hash) / 1000.0; *ind = null && hash % 5 == 0 ? SQL_NULL_DATA : 0; } bool verify(const char* v1, SQLINTEGER ind1, const char* v2, SQLINTEGER ind2, unsigned n) { if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) return true; if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) if (memcmp(v1, v2, n) == 0) return true; if (ind1 == SQL_NULL_DATA) v1 = "NULL"; if (ind2 == SQL_NULL_DATA) v2 = "NULL"; ndbout << "verify failed: got "; if (ind1 == SQL_NULL_DATA) ndbout << "NULL"; else cleanprint(v1, n); ndbout << " != "; if (ind2 == SQL_NULL_DATA) ndbout << "NULL"; else cleanprint(v2, n); ndbout << endl; return false; } bool verify(long v1, SQLINTEGER ind1, long v2, SQLINTEGER ind2) { char buf1[40], buf2[40]; if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) return true; if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) if (v1 == v2) return true; if (ind1 == SQL_NULL_DATA) strcpy(buf1, "NULL"); else sprintf(buf1, "%ld", v1); if (ind2 == SQL_NULL_DATA) strcpy(buf2, "NULL"); else sprintf(buf2, "%ld", v2); ndbout << "verify failed: got " << buf1 << " != " << buf2 << endl; return false; } bool verify(double v1, SQLINTEGER ind1, double v2, SQLINTEGER ind2) { char buf1[40], buf2[40]; if (ind1 == SQL_NULL_DATA && ind2 == SQL_NULL_DATA) return true; if (ind1 != SQL_NULL_DATA && ind2 != SQL_NULL_DATA) if (fabs(v1 - v2) < 1) // XXX return true; if (ind1 == SQL_NULL_DATA) strcpy(buf1, "NULL"); else sprintf(buf1, "%.10f", v1); if (ind2 == SQL_NULL_DATA) strcpy(buf2, "NULL"); else sprintf(buf2, "%.10f", v2); ndbout << "verify failed: got " << buf1 << " != " << buf2 << endl; return false; }};#if defined(NDB_SOLARIS) || defined(NDB_LINUX) || defined(NDB_MACOSX)#define HAVE_SBRK#else#undef HAVE_SBRK#endifstruct Timer { Timer() : m_cnt(0), m_calls(0), m_on(0), m_msec(0)#ifndef NDB_WIN32 , m_brk(0), m_incr(0)#endif { } void timerOn() { m_cnt = 0; m_calls = 0; m_on = NdbTick_CurrentMillisecond();#ifdef HAVE_SBRK m_brk = (int)sbrk(0);#endif } void timerOff() { m_msec = NdbTick_CurrentMillisecond() - m_on; if (m_msec <= 0) m_msec = 1;#ifdef HAVE_SBRK m_incr = (int)sbrk(0) - m_brk; if (m_incr < 0) m_incr = 0;#endif } void timerCnt(unsigned cnt) { m_cnt += cnt; } void timerCnt(const Timer& timer) { m_cnt += timer.m_cnt; m_calls += timer.m_calls; } friend NdbOut& operator<<(NdbOut& out, const Timer& timer) { out << timer.m_cnt << " ( " << 1000 * timer.m_cnt / timer.m_msec << "/sec )";#ifdef HAVE_SBRK out << " - " << timer.m_incr << " sbrk"; if (opt.m_namecnt != 0) { // per case meaningless if many cases if (timer.m_cnt > 0) out << " ( " << timer.m_incr / timer.m_cnt << "/cnt )"; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?