/* ================================================================= Copyright (C) 2013 BizStation Corp All rights reserved. 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. ================================================================= */ //#define BOOST_TEST_MODULE #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace bzs::db::protocol::tdap::client; using namespace bzs::db::protocol::tdap; using namespace std; #define TDAP #ifdef TDAP #define PROTOCOL _T("tdap") #else #define PROTOCOL _T("btrv") #endif static _TCHAR HOSTNAME[MAX_PATH] = { _T("127.0.0.1") }; #define DBNAME _T("test") #define BDFNAME _T("test") // #define ISOLATION_REPEATABLE_READ #define ISOLATION_READ_COMMITTED static _TCHAR g_uri[MAX_PATH]; static _TCHAR g_userName[MYSQL_USERNAME_MAX + 1]={0x00}; static _TCHAR g_password[MAX_PATH]={0x00}; static const short fdi_id = 0; static const short fdi_name = 1; boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]); boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) { for (int i = 1; i < argc; ++i) { if (strstr(argv[i], "--host=") == argv[i]) { #ifdef _UNICODE MultiByteToWideChar(CP_ACP, (CP_ACP == CP_UTF8) ? 0 : MB_PRECOMPOSED, argv[i] + 7, -1, HOSTNAME, MAX_PATH); #else strcpy_s(HOSTNAME, MAX_PATH, argv[i] + 7); #endif } if (strstr(argv[i], "--user=") == argv[i]) { #ifdef _UNICODE MultiByteToWideChar(CP_ACP, (CP_ACP == CP_UTF8) ? 0 : MB_PRECOMPOSED, argv[i] + 7, -1, g_userName, MYSQL_USERNAME_MAX+1); #else strcpy_s(g_userName, MYSQL_USERNAME_MAX+1, argv[i] + 7); #endif } if (strstr(argv[i], "--pwd=") == argv[i]) { #ifdef _UNICODE MultiByteToWideChar(CP_ACP, (CP_ACP == CP_UTF8) ? 0 : MB_PRECOMPOSED, argv[i] + 6, -1, g_password, MAX_PATH); #else strcpy_s(g_password, MAX_PATH, argv[i] + 6); #endif } } printf("Transactd test ... \nMay look like progress is stopped, \n" "but it is such as record lock test, please wait.\n"); return 0; } const _TCHAR* makeUri(const _TCHAR* protocol, const _TCHAR* host, const _TCHAR* dbname, const _TCHAR* dbfile=_T("")) { connectParams cp(protocol, host, dbname, dbfile, g_userName, g_password); _tcscpy(g_uri, cp.uri()); /*if (dbfile) _stprintf_s(g_uri, MAX_PATH, _T("%s://%s/%s?dbfile=%s"), protocol, host, dbname, dbfile); else _stprintf_s(g_uri, MAX_PATH, _T("%s://%s/%s"), protocol, host, dbname);*/ return g_uri; } class fixture { mutable database* m_db; public: fixture() : m_db(NULL) { nsdatabase::setCheckTablePtr(true); m_db = database::create(); if (!m_db) printf("Error database::create()\n"); } ~fixture() { if (m_db) { // Test for SWIG interface m_db->release(); // Test for c++ // database::destroy(m_db); } } ::database* db() const { return m_db; } }; #ifdef _WIN32 class fixtureKanji { mutable database* m_db; public: fixtureKanji() : m_db(NULL) { nsdatabase::setExecCodePage(932); nsdatabase::setCheckTablePtr(true); m_db = database::create(); if (!m_db) printf("Error database::create()\n"); } ~fixtureKanji() { if (m_db) m_db->release(); } ::database* db() const { return m_db; } }; #else typedef fixture fixtureKanji; #endif class fixtureQuery { database_ptr m_db; public: fixtureQuery() { m_db = createDatabaseObject(); if (!m_db) printf("Error database::create()\n"); connectParams param(PROTOCOL, HOSTNAME, _T("querytest"), _T("test"), g_userName, g_password); param.setMode(TD_OPEN_NORMAL); prebuiltData(m_db, param); } ~fixtureQuery() {} database* db() const { return m_db.get(); } }; table* openTable(database* db, short dbmode = TD_OPEN_NORMAL, short tbmode = TD_OPEN_NORMAL) { db->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, dbmode); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); table* tb = db->openTable(_T("user"), tbmode); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); return tb; } void testDropDatabase(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "drop stat = " << db->stat()); } void testClone(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); database* db2 = db->clone(); BOOST_CHECK_MESSAGE(db2 != NULL, "createNewDataBase stat = " << db->stat()); db2->close(); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(db2->stat() == 0, "db2 close stat = " << db2->stat()); db->close(); BOOST_CHECK_MESSAGE(db->stat() == 0, "db close stat = " << db->stat()); table* tb = db2->openTable(_T("user"), TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db2->stat(), "openTable" << db2->stat()); if (db2) db2->release(); bool ret = nsdatabase::testTablePtr(tb); BOOST_CHECK_MESSAGE(ret == true, "testTablePtr"); tb->release(); ret = nsdatabase::testTablePtr(tb); BOOST_CHECK_MESSAGE(ret == false, "testTablePtr"); } void testCreateNewDataBase(database* db) { db->create(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME)); if (db->stat() == STATUS_TABLE_EXISTS_ERROR) { testDropDatabase(db); db->create(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME)); } BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase stat = " << db->stat()); // create table db->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase 1 stat = " << db->stat()); dbdef* def = db->dbDef(); if (def) { /* user table */ tabledef td; memset(&td, 0, sizeof(tabledef)); td.setTableName(_T("user")); td.setFileName(_T("user.dat")); td.id = 1; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; #ifdef _WIN32 td.charsetIndex = CHARSET_CP932; #else td.charsetIndex = CHARSET_UTF8; #endif def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable stat = " << def->stat()); fielddef* fd = def->insertField(1, 0); fd->setName(_T("id")); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 1 stat = " << def->stat()); fd = def->insertField(1, 1); fd->setName(_T("name")); fd->len = (ushort_td)33; //test padChar only string or wstring fd->type = ft_string; fd->setPadCharSettings(true, false); BOOST_CHECK(fd->usePadChar() == true); BOOST_CHECK(fd->trimPadChar() == false); fd->setPadCharSettings(false, true); BOOST_CHECK(fd->usePadChar() == false); BOOST_CHECK(fd->trimPadChar() == true); fd->type = ft_zstring; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); fd = def->insertField(1, 2); fd->setName(_T("select")); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); fd = def->insertField(1, 3); fd->setName(_T("in")); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); keydef* kd = def->insertKey(1, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 3 stat = " << def->stat()); /* group table */ memset(&td, 0, sizeof(tabledef)); td.setTableName(_T("group")); td.setFileName(_T("group")); td.id = 2; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable stat = " << def->stat()); fd = def->insertField(2, 0); fd->setName(_T("id")); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(2); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 1 stat = " << def->stat()); fd = def->insertField(2, 1); fd->setName(_T("name")); fd->type = ft_zstring; fd->len = (ushort_td)33; def->updateTableDef(2); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); kd = def->insertKey(2, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; def->updateTableDef(2); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 3 stat = " << def->stat()); } } void testVersion(database* db) { db->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "Version connect stat = " << db->stat()); if (0 == db->stat()) { btrVersions vv; db->getBtrVersion(&vv); BOOST_CHECK_MESSAGE(0 == db->stat(), "Version"); if (_tcscmp(PROTOCOL, _T("tdap")) == 0) { BOOST_CHECK_MESSAGE( atoi(CPP_INTERFACE_VER_MAJOR) == vv.versions[0].majorVersion, "clent_Major = " << vv.versions[0].majorVersion); BOOST_CHECK_MESSAGE( atoi(CPP_INTERFACE_VER_MINOR) == vv.versions[0].minorVersion, "clent_Miner = " << vv.versions[0].minorVersion); BOOST_CHECK_MESSAGE((int)'N' == (int)vv.versions[0].type, "clent_Type = " << vv.versions[0].type); BOOST_CHECK_MESSAGE( ((5 == vv.versions[1].majorVersion) || (10 == vv.versions[1].majorVersion)), "mysql_server_Major = " << vv.versions[1].majorVersion); BOOST_CHECK_MESSAGE( ((5 <= vv.versions[1].minorVersion) || (0 == vv.versions[1].minorVersion)), "mysql_server_Miner = " << vv.versions[1].minorVersion); BOOST_CHECK_MESSAGE((int)'M' == (int)vv.versions[1].type, "mysql_server_Type = " << vv.versions[1].type); BOOST_CHECK_MESSAGE( TRANSACTD_VER_MAJOR == vv.versions[2].majorVersion, "server_Major = " << vv.versions[2].majorVersion); BOOST_CHECK_MESSAGE( TRANSACTD_VER_MINOR == vv.versions[2].minorVersion, "server_Miner = " << vv.versions[2].minorVersion); BOOST_CHECK_MESSAGE((int)'T' == (int)vv.versions[2].type, "server_Type = " << vv.versions[2].type); } } } void testInsert(database* db) { table* tb = openTable(db); if (tb->recordCount() == 0) { tb->clearBuffer(); tb->setFV((short)0, _T("1")); tb->setFV((short)1, _T("kosaka")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert"); } //test invalid keyNum tb->clearBuffer(); tb->setFV((short)0, _T("2")); tb->setKeyNum(10); tb->insert(); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum insert"); tb->setKeyNum(0); db->beginTrn(); int n = 1; tb->seekLast(); if (tb->stat() == 0) n = tb->getFVint(fdi_id) + 1; tb->beginBulkInsert(BULKBUFSIZE); for (int i = n; i < 20002 + n - 1; i++) { tb->clearBuffer(); tb->setFV((short)0, i); tb->setFV((short)1, i); if (i == 87170) i = 87170; tb->insert(); } tb->commitBulkInsert(); db->endTrn(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "Insert2"); tb->release(); } void findNextLoop(table* tb, int start, int end) { while (start < end) { BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat = " << tb->stat()); if (tb->stat()) break; BOOST_CHECK_MESSAGE(start == tb->getFVint(fdi_id), "find value " << start << " bad = " << tb->getFVint(fdi_id)); tb->findNext(true); ++start; } BOOST_CHECK_MESSAGE(0 != tb->stat(), "findNext end stat = " << tb->stat()); } void testFind(database* db) { table* tb = openTable(db); //test invalid keyNum tb->clearBuffer(); tb->setKeyNum(10); tb->setFilter(_T("id >= 10 and id < 20000"), 1, 0); int v = 10; tb->setFV((short)0, v); tb->find(table::findForword); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum find"); tb->setKeyNum(0); tb->clearBuffer(); tb->setFilter(_T("id >= 10 and id < 20000"), 1, 0); v = 10; tb->setFV((short)0, v); tb->find(table::findForword); findNextLoop(tb, v, 20000); // backforword tb->clearBuffer(); v = 19999; tb->setFV((short)0, v); tb->find(table::findBackForword); int i = v; while (i >= 10) { BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat = " << tb->stat()); if (tb->stat()) break; BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "find value " << i); tb->findPrev(true); // 11 ~ 19 --i; } tb->clearBuffer(); v = 20000; tb->setFV((short)0, v); tb->find(table::findForword); BOOST_CHECK_MESSAGE(STATUS_EOF == tb->stat(), "find stat"); tb->release(); } void testFindNext(database* db) { table* tb = openTable(db); tb->setKeyNum(0); tb->clearBuffer(); tb->setFilter(_T("id >= 10 and id < 20000"), 1, 0); int v = 10; tb->setFV((short)0, v); tb->seekGreater(true); BOOST_CHECK_MESSAGE(v == tb->getFVint(fdi_id), "findNext GetGreater"); for (int i = v + 1; i < 20000; i++) { tb->findNext(true); // 11 ~ 19 BOOST_CHECK_MESSAGE(0 == tb->stat(), "findNext stat()" << tb->stat()); if (tb->stat()) break; BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "findNext value"); } tb->release(); } void testFindIn(database* db) { table* tb = openTable(db); //test invalid keyNum tb->clearBuffer(); queryBase q; q.addSeekKeyValue(_T("10"), true); tb->setQuery(&q); BOOST_CHECK_MESSAGE(0 == tb->stat(), "find in stat = " << tb->stat()); tb->setKeyNum(10); tb->find(); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum seekKeyValue"); tb->setKeyNum(0); tb->clearBuffer(); q.reset(); q.addSeekKeyValue(_T("10"), true); q.addSeekKeyValue(_T("300000")); q.addSeekKeyValue(_T("50")); q.addSeekKeyValue(_T("-1")); q.addSeekKeyValue(_T("80")); q.addSeekKeyValue(_T("5000")); tb->setQuery(&q); BOOST_CHECK_MESSAGE(0 == tb->stat(), "find in stat = " << tb->stat()); tb->find(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "find in stat = " << tb->stat()); BOOST_CHECK_MESSAGE(tb->getFVint(fdi_id) == 10, "find in 10"); tb->findNext(); BOOST_CHECK_MESSAGE(tb->stat() == 4, "find in 300000 stat =" << tb->stat()); _TCHAR msg[1024]; tb->keyValueDescription(msg, 1024); int comp = _tcscmp(_T("table:user\nstat:4\nid = 300000\n"), msg); BOOST_CHECK_MESSAGE(comp == 0, "find in keyValueDescription"); tb->findNext(); BOOST_CHECK_MESSAGE(tb->getFVint(fdi_id) == 50, "find in 50"); tb->findNext(); BOOST_CHECK_MESSAGE(tb->stat() == 4, "find in -1"); tb->keyValueDescription(msg, 1024); comp = _tcscmp(_T("table:user\nstat:4\nid = -1\n"), msg); BOOST_CHECK_MESSAGE(comp == 0, "find in keyValueDescription"); tb->findNext(); BOOST_CHECK_MESSAGE(tb->getFVint(fdi_id) == 80, "find in 80"); tb->findNext(); BOOST_CHECK_MESSAGE(tb->getFVint(fdi_id) == 5000, "find in 5000"); tb->findNext(); BOOST_CHECK_MESSAGE(STATUS_EOF == tb->stat(), "find in more"); // Many params _TCHAR buf[20]; for (int j = 1; j <= 10000; ++j) { _ltot_s(j, buf, 20, 10); q.addSeekKeyValue(buf, (j == 1)/* reset */); } tb->setQuery(&q); BOOST_CHECK_MESSAGE(0 == tb->stat(), "find in stat = " << tb->stat()); int i = 0; tb->find(); while (0 == tb->stat()) { ++i; BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "findNext in value " << i << " = " << tb->getFVint(fdi_id)); if (i==9999) i = 9999; tb->findNext(true); } BOOST_CHECK_MESSAGE(i == 10000, "findNext in count 10000 != " << i); BOOST_CHECK_MESSAGE(9 == tb->stat(), "find in end stat = " << tb->stat()); // LogicalCountLimit q.addField(_T("id")); tb->setQuery(&q); tb->find(); i = 0; while (0 == tb->stat()) { BOOST_CHECK_MESSAGE(++i == tb->getFVint(fdi_id), "findNext in value"); tb->findNext(true); } BOOST_CHECK_MESSAGE(i == 10000, "findNext in count"); BOOST_CHECK_MESSAGE(9 == tb->stat(), "find in end stat = " << tb->stat()); tb->release(); } void testPrepare(database* db) { table* tb = openTable(db); queryBase q; q.queryString(_T("id >= ? and id < ?")); q.reject(1).limit(0); pq_handle stmt = tb->prepare(&q); const _TCHAR* vs[2]; int nn = makeSupplyValues(vs, 2, _T("10"), _T("20000")); //Test too short supply values bool ret = supplyValues(stmt, vs, nn -1); //stmt->supplyValues(vs, nn); Bad BOOST_CHECK_MESSAGE(ret == false, "supplyValues short"); //Test supply values ret = supplyValues(stmt, vs, nn); BOOST_CHECK_MESSAGE(ret == true, "supplyValues true"); int v = 10; tb->setFV((short)0, v); tb->find(table::findForword); findNextLoop(tb, v, 20000); supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("10000"))); //stmt->supplyValues(vs, nn); Bad tb->setPrepare(stmt); v = 100; tb->setFV((short)0, v); tb->find(table::findForword); findNextLoop(tb, v, 10000); const _TCHAR* values[11]; int n = makeSupplyValues(values, 11, _T("abc"), _T("efg"), _T("efg") , _T("abc"), _T("efg"), _T("efg") , _T("abc"), _T("efg"), _T("efg") , _T("abc"), _T("efg")); BOOST_CHECK_MESSAGE(n == 11, "makeSupplyValues"); tb->release(); } void testPrepareServer(database* db) { table* tb = openTable(db); queryBase q; //test invalid keyNum tb->setKeyNum(10); tb->clearBuffer(); q.queryString(_T("id >= ? and id < ?")).reject(0xFFFF).limit(0); pq_handle stmt = tb->prepare(&q, true); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum prepare"); tb->setKeyNum(0); stmt = tb->prepare(&q, true); BOOST_CHECK_MESSAGE(0 == tb->stat(), "prepare stat"); if (tb->stat()) return ; const _TCHAR* vs[2]; bool ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("10"), _T("200"))); //stmt->supplyValues(vs, nn); Bad BOOST_CHECK_MESSAGE(ret == true, "supplyValues true"); tb->setPrepare(stmt); BOOST_CHECK_MESSAGE(tb->stat() == 0, "setQuery stmt"); int v = 10; tb->setFV((short)0, v); // Test Bad direction tb->find(table::findBackForword); BOOST_CHECK_MESSAGE(1 == tb->stat(), "find direction not equal prepare"); tb->find(table::findForword); findNextLoop(tb, v, 200); ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("3000"))); BOOST_CHECK_MESSAGE(ret == true, "supplyValues true"); tb->setPrepare(stmt); BOOST_CHECK_MESSAGE(tb->stat() == 0, "setQuery stmt"); v = 100; tb->setFV((short)0, v); tb->find(table::findForword); findNextLoop(tb, v, 3000); // No seek with ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("50"), _T("100"))); BOOST_CHECK_MESSAGE(ret == true, "supplyValues "); tb->setPrepare(stmt); v = 50; tb->setFV((short)0, v); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seek"); tb->findNext(false); findNextLoop(tb, v, 100); // RecordCount ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("50"), _T("100"))); BOOST_CHECK_MESSAGE(ret == true, "supplyValues "); tb->setPrepare(stmt); uint_td num = tb->recordCount(false); BOOST_CHECK_MESSAGE(num == 50, "recordCount "); // Multi prepare statement q.reset(); q.queryString(_T("id < ?")); q.reject(0xFFFF).limit(0); pq_handle stmt2 = tb->prepare(&q, true); ret = supplyValues(stmt2, vs, makeSupplyValues(vs, 1, _T("50"))); BOOST_CHECK_MESSAGE(ret == true, "supplyValues "); tb->setPrepare(stmt2); v = 1; tb->setFV((short)0, v); tb->find(); findNextLoop(tb, v, 50); ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("3000"))); BOOST_CHECK_MESSAGE(ret == true, "supplyValues "); tb->setPrepare(stmt); v = 100; tb->setFV((short)0, v); tb->find(table::findForword); findNextLoop(tb, v, 3000); tb->release(); } void testGetPercentage(database* db) { table* tb = openTable(db); tb->clearBuffer(); int vv = 10001; tb->setFV((short)0, vv); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual"); percentage_td per = tb->getPercentage(); BOOST_CHECK_MESSAGE(true == (1200 > abs(5000 - per)), "GetPercentage"); tb->release(); } void testMovePercentage(database* db) { table* tb = openTable(db); tb->clearBuffer(); //test invalid keyNum tb->setKeyNum(10); tb->seekByPercentage(5000); // 50% BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum prepare"); tb->setKeyNum(0); tb->seekByPercentage(5000); // 50% BOOST_CHECK_MESSAGE(0 == tb->stat(), "MovePercentage"); // If mainus is less than 500 then ok. BOOST_CHECK_MESSAGE(true == (3000 > abs(10001 - tb->getFVint(fdi_id))), "MovePercentage 1"); tb->release(); } void testGetEqual(database* db) { table* tb = openTable(db); //test invalid keyNum tb->setKeyNum(10); tb->clearBuffer(); tb->setFV((short)0, 10); tb->seek(); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum seek"); db->beginSnapshot(); tb->setKeyNum(0); for (int i = 2; i < 20002; i++) { tb->clearBuffer(); tb->setFV((short)0, i); tb->seek(); BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetEqual"); } db->endSnapshot(); tb->release(); } void testGetNext(database* db) { table* tb = openTable(db); for (int j = 0; j < 1; j++) { db->beginSnapshot(); int vv = 2; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seek(); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetNext"); for (int i = 3; i < 20002; i++) { tb->seekNext(); BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetNext id: " << i << " bad = " << tb->getFVint(fdi_id)); if (i != tb->getFVint(fdi_id)) break; } db->endSnapshot(); } tb->release(); } void testGetPrevious(database* db) { table* tb = openTable(db); // in-snapshot db->beginSnapshot(); int vv = 20001; tb->clearBuffer(); tb->setFV((short)0, vv); tb->seek(); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetPrevious"); for (int i = 20000; i > 1; i--) { tb->seekPrev(); BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetPrevious id: " << i << " bad = " << tb->getFVint(fdi_id)); if (i != tb->getFVint(fdi_id)) break; } tb->seekPrev(); BOOST_CHECK_MESSAGE(_tstring(_T("kosaka")) == _tstring(tb->getFVstr(1)), "GetPrevious kosaka"); db->endSnapshot(); //without snapshot vv = 20001; tb->clearBuffer(); tb->setFV((short)0, vv); tb->seek(); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetPrevious"); for (int i = 20000; i > 1; i--) { tb->seekPrev(); BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetPrevious id: " << i << " bad = " << tb->getFVint(fdi_id)); if (i != tb->getFVint(fdi_id)) break; } tb->seekPrev(); BOOST_CHECK_MESSAGE(_tstring(_T("kosaka")) == _tstring(tb->getFVstr(1)), "GetPrevious kosaka"); tb->release(); } void testGetGreater(database* db) { table* tb = openTable(db); int vv = 15000; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seekGreater(true); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetGreater true"); tb->seekNext(); BOOST_CHECK_MESSAGE(vv + 1 == tb->getFVint(fdi_id), "GetGreater GetNext"); vv = 14000; tb->clearBuffer(); tb->setFV((short)0, vv); tb->seekGreater(false); BOOST_CHECK_MESSAGE(vv + 1 == tb->getFVint(fdi_id), "GetGreater false"); tb->seekPrev(); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetGreater GetPrevious"); tb->release(); } void testGetLessThan(database* db) { table* tb = openTable(db); int vv = 15000; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seekLessThan(true); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetLessThan true"); tb->seekNext(); BOOST_CHECK_MESSAGE(vv + 1 == tb->getFVint(fdi_id), "GetLessThan GetNext"); vv = 14000; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seekLessThan(false); BOOST_CHECK_MESSAGE(vv - 1 == tb->getFVint(fdi_id), "GetLessThan false"); tb->seekPrev(); BOOST_CHECK_MESSAGE(vv - 2 == tb->getFVint(fdi_id), "GetLessThan GetPrevious"); tb->release(); } void testGetFirst(database* db) { table* tb = openTable(db); tb->clearBuffer(); //test invalid keyNum tb->setKeyNum(10); tb->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum seekFirst"); tb->setKeyNum(0); tb->seekFirst(); BOOST_CHECK_MESSAGE(_tstring(_T("kosaka")) == _tstring(tb->getFVstr(1)), "GetFirst"); tb->release(); } void testGetLast(database* db) { table* tb = openTable(db); tb->clearBuffer(); //test invalid keyNum tb->setKeyNum(10); tb->seekLast(); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum seekFirst"); tb->setKeyNum(0); tb->seekLast(); BOOST_CHECK_MESSAGE(20002 == tb->getFVint(fdi_id), "GetLast"); tb->release(); } void testMovePosition(database* db) { table* tb = openTable(db); int vv = 15000; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seekLessThan(true); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetLessThan "); bookmark_td pos = tb->bookmark(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetBookMark"); vv = 14000; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seekLessThan(false); BOOST_CHECK_MESSAGE(vv - 1 == tb->getFVint(fdi_id), "GetLessThan false"); tb->seekPrev(); BOOST_CHECK_MESSAGE(vv - 2 == tb->getFVint(fdi_id), "GetLessThan GetPrevious"); tb->seekByBookmark(pos); BOOST_CHECK_MESSAGE(15000 == tb->getFVint(fdi_id), "MovePosition"); //test invalid keyNum tb->setKeyNum(10); tb->seekByBookmark(pos); BOOST_CHECK_MESSAGE(STATUS_INVALID_KEYNUM == tb->stat(), "Invalid keynum seekByBookmark stat = " << tb->stat()); tb->release(); } void testUpdate(database* db) { table* tb = openTable(db); db->beginTrn(); // test of ncc int v = 5; tb->clearBuffer(); tb->setFV(fdi_id, v); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual U"); v = 30000; tb->setFV(fdi_id, v); tb->update(table::changeCurrentNcc); // 5 -> 30000 cur 5 BOOST_CHECK_MESSAGE(0 == tb->stat(), "UpDate00"); tb->seekNext(); // next 5 BOOST_CHECK_MESSAGE(6 == tb->getFVint(fdi_id), "UpDate0"); v = 19999; tb->setFV(fdi_id, v); tb->seek(); BOOST_CHECK_MESSAGE(v == tb->getFVint(fdi_id), "UpDate1"); v = 5; tb->setFV(fdi_id, v); tb->update(table::changeCurrentCc); // 19999 -> 5 cur 5 BOOST_CHECK_MESSAGE(0 == tb->stat(), "UpDate11"); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "UpDate21"); BOOST_CHECK_MESSAGE(6 == tb->getFVint(fdi_id), "UpDate2"); v = 19999; tb->setFV(fdi_id, v); tb->update(table::changeCurrentCc); // 6 -> 19999 cur 19999 tb->seekPrev(); // prev 19999 BOOST_CHECK_MESSAGE(v - 1 == tb->getFVint(fdi_id), "UpDate3"); v = 10; tb->clearBuffer(); tb->setFV(fdi_id, v); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual U10"); tb->seekNext(); BOOST_CHECK_MESSAGE(11 == tb->getFVint(fdi_id), "GetEqual Next"); for (int i = 10; i < 19999; i++) { tb->clearBuffer(); tb->setFV(fdi_id, i); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual U"); int v = i + 1; tb->setFV((short)1, v); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "UpDate"); } db->endTrn(); // check update in key v = 8; tb->setFV(fdi_id, v); tb->setFV(fdi_name, _T("ABC")); tb->update(table::changeInKey); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update changeInKey"); tb->clearBuffer(); tb->setFV(fdi_id, v); tb->seek(); BOOST_CHECK_MESSAGE(_tcscmp(_T("ABC"), tb->getFVstr(fdi_name)) == 0, "update changeInKey2"); tb->release(); } void testSnapshot(database* db) { table* tb = openTable(db); table* tbg = db->openTable(_T("group"), TD_OPEN_NORMAL); database* db2 = database::create(); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); table* tb2 = openTable(db2); table* tbg2 = db2->openTable(_T("group"), TD_OPEN_NORMAL); /* No locking repeatable read */ /* -------------------------------------------------- */ db->beginSnapshot(); // CONSISTENT_READ is default BOOST_CHECK_MESSAGE(0 == db->stat(), "beginSnapShot"); db->beginTrn(); BOOST_CHECK_MESSAGE(STATUS_ALREADY_INSNAPSHOT == db->stat(), "Invalid beginSnapshot"); tb->setKeyNum(0); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst"); _tstring firstValue = tb->getFVstr(fdi_name); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext"); BOOST_CHECK_MESSAGE(2 == tb->getFVint(fdi_id), "seekNext"); tbg->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_EOF == tbg->stat(), "seekFirst tbg"); BOOST_CHECK_MESSAGE(0 == tbg->recordCount(false), "seekFirst tbg"); // Change data by another connection. change 2 tables. tb2->setKeyNum(0); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->setFV(fdi_name, tb2->getFVint(fdi_name) + 1); tb2->update(); //Change success BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update stat = " << tb2->stat()); tbg2->setFV(fdi_id, 1); tbg2->setFV(fdi_name, _T("ABC")); tbg2->insert(); BOOST_CHECK_MESSAGE(0 == tbg2->stat(), "tbg2->insert"); // in-snapshot repeatable read check same value tb->seekFirst(); _tstring secondValue = tb->getFVstr(fdi_name); BOOST_CHECK_MESSAGE(0 == tb->stat(), "secondValue"); BOOST_CHECK_MESSAGE(secondValue == firstValue, "repeatableRead"); tbg->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_EOF == tbg->stat(), "seekFirst tbg"); BOOST_CHECK_MESSAGE(0 == tbg->recordCount(false), "seekFirst tbg"); // test update in snapshot tb->update(); BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb->stat(), "snapshot update stat = " << tb->stat()); // test insert in snapshot tb->setFV(fdi_id, 0); tb->insert(); BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb->stat(), "snapshot insert stat = " << tb->stat()); //test phantom read tb2->setFV(fdi_id, 29999); tb2->insert(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "phantom insert"); tb->setFV(fdi_id, 29999); tb->seek(); BOOST_CHECK_MESSAGE(STATUS_NOT_FOUND_TI == tb->stat(), "phantom read"); // clean up tb2->setFV(fdi_id, 29999); tb2->seek(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "seek stat = " << tb2->stat()); tb2->del(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "del stat = " << tb2->stat()); db->endSnapshot(); BOOST_CHECK_MESSAGE(0 == db->stat(), "endSnapShot"); // After snapshot, db can read new versions. tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); BOOST_CHECK_MESSAGE(1 == tb->getFVint(fdi_name), "read new value = 1"); tbg->seekFirst(); BOOST_CHECK_MESSAGE(0 == tbg->stat(), "seekFirst tbg"); BOOST_CHECK_MESSAGE(1 == tbg->recordCount(false), "seekFirst tbg"); //test gap lock db->beginSnapshot(MULTILOCK_GAP_SHARE); tb->seekLast(); // id = 30000 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekLast"); tb->seekPrev(); // id = 20002 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev"); tb->seekPrev(); // id = 20001 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev"); tb2->setFV(fdi_id, 29999); tb2->insert(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert stat = " << tb2->stat()); db->endSnapshot(); //test gap lock db->beginSnapshot(MULTILOCK_NOGAP_SHARE); tb->seekLast(); // id = 30000 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekLast"); tb->seekPrev(); // id = 20002 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev"); tb->seekPrev(); // id = 20001 BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev"); tb2->setFV(fdi_id, 20002); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert"); tb2->seekLast(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert"); db->endSnapshot(); tbg->release(); tbg2->release(); tb->release(); tb2->release(); database::destroy(db2); } void testConflict(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); table* tb2 = openTable(db2); tb->setKeyNum(0); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); /* -------------------------------------------------- Change Index field -------------------------------------------------- */ // Change data by another connection tb2->setKeyNum(0); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->setFV(fdi_id, tb2->getFVint(fdi_id) - 10); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update("); /* -------------------------------------------------- */ // Change same record data by original connection tb->setFV(fdi_id, tb->getFVint(fdi_id) - 8); tb->update(); BOOST_CHECK_MESSAGE(STATUS_CHANGE_CONFLICT == tb->stat(), "tb->update("); /* -------------------------------------------------- */ /* -------------------------------------------------- */ /* Change Non index field */ /* -------------------------------------------------- */ // Change data by another connection tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->setFV(fdi_name, tb2->getFVint(fdi_name) - 10); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update("); /* -------------------------------------------------- */ // Change same record data by original connection tb->setFV(fdi_name, tb->getFVint(fdi_name) - 8); tb->update(); BOOST_CHECK_MESSAGE(STATUS_CHANGE_CONFLICT == tb->stat(), "tb->update("); /* -------------------------------------------------- */ tb->release(); tb2->release(); database::destroy(db2); } /* isoration Level ISO_REPEATABLE_READ */ void testTransactionLockRepeatable(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); table* tb2 = openTable(db2); db->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // Test Invalid operation db->beginSnapshot(); BOOST_CHECK_MESSAGE(STATUS_ALREADY_INTRANSACTION == db->stat(), "Invalid beginSnapshot"); /* -------------------------------------------------*/ /* Test Read with lock */ /* -------------------------------------------------*/ // lock(X) the first record tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); // Add lock(X) the second record tb->seekNext(); // No transaction user can read allways. Use consistent_read tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); tb2->seekNext(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); // The second transaction user can not lock same record. db2->beginTrn(); tb2->setKeyNum(0); // Try lock(X) tb2->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst"); db2->endTrn(); db->endTrn(); /* -------------------------------------------------*/ /* Test single record lock and Transaction lock */ /* -------------------------------------------------*/ // lock(X) non-transaction tb2->seekFirst(ROW_LOCK_X); db->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // Try lock(X) tb->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst"); // Remove lock(X) tb2->seekFirst(); // Retry lock(X) tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->setFV(fdi_name, _T("ABC")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); // No transaction user read can read allways. Use consistent_read tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); BOOST_CHECK_MESSAGE(_tstring(_T("ABC")) != _tstring(tb2->getFVstr(fdi_name)), "consistent_read"); /* -------------------------------------------------*/ /* Test Transaction lock and Transaction lock */ /* -------------------------------------------------*/ db2->beginTrn(); BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn"); // try lock(X) tb2->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst"); // Try unlock updated record. Con not unlock updated record. tb->unlock(); // try lock(X) tb2->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst"); db2->endTrn(); db->endTrn(); /* -------------------------------------------------*/ /* Test phantom read */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // read last row tb->seekLast(); //lock(X) last id = 30000 BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast"); tb->seekPrev(); //Add lock(X) BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); int last2 = tb->getFVint(fdi_id); // insert test row tb2->setFV(fdi_id, 29999); tb2->insert(); //Can not insert by gap lock BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->insert"); tb->seekLast(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast"); tb->seekPrev(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); BOOST_CHECK_MESSAGE(last2 == tb->getFVint(fdi_id), "phantom read"); db->endTrn(); /* -------------------------------------------------*/ /* Test use shared lock option */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn1"); db2->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn2"); tb->seekLast(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast"); tb2->seekLast(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekLast"); tb->seekPrev();//Lock(X) BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); tb2->seekPrev(ROW_LOCK_S); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekPrev"); tb->seekPrev(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); int id = tb->getFVint(fdi_id); tb2->setFV(fdi_id, id); tb2->seek(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek"); db2->endTrn(); db->endTrn(); /* -------------------------------------------------*/ /* Test Abort */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_REPEATABLE_READ); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // lock(X) tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->setFV(fdi_name, _T("EFG")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); // move from first record. tb->seekNext(); db->abortTrn(); tb2->setKeyNum(0); tb2->seekFirst(); BOOST_CHECK_MESSAGE(_tcscmp(tb2->getFVstr(fdi_name), _T("ABC")) == 0, "tb->seekFirst"); /* -------------------------------------------------*/ /* Test Query and locks Multi record lock */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_REPEATABLE_READ); // Test find records are lock. query q; q.where(_T("id"), _T("<="), 15).and_(_T("id"), _T("<>"), 13) .reject(0xFFFF); tb->setQuery(&q); tb->setFV(fdi_id, 12); tb->find(); while (tb->stat() == 0) tb->findNext(); BOOST_CHECK_MESSAGE(15 == tb->getFVint(fdi_id), "find last id"); //all records locked for (int i = 12 ; i <= 16; ++i) { tb2->setFV(fdi_id, i); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seek"); } db->endTrn(); tb->release(); tb2->release(); database::destroy(db2); } void testBug_015(database* db) { table* tb = openTable(db); db->beginTrn(SINGLELOCK_NOGAP); tb->seekFirst(); // lock(X) tb->unlock(); tb->seekNext(); /* Here! InnoDB issues an error message, please check the MySQL error log. [InnoDB: Error: unlock row could not find a 3 mode lock on the record] */ db->endTrn(); tb->release(); } /* READ_COMMITTED support select lock type */ void testIssue_016(database* db) { table* tb = openTable(db); db->beginTrn(MULTILOCK_NOGAP); tb->seekFirst(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst S"); tb->seekNext(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext S"); tb->seekNext(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext X"); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); db->endTrn(); db->beginTrn(MULTILOCK_GAP); tb->seekFirst(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst S"); tb->seekNext(ROW_LOCK_S); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext S"); tb->seekNext(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext X"); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); db->endTrn(); tb->release(); } /* isoration Level ISO_READ_COMMITED */ void testTransactionLockReadCommited(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); table* tb2 = openTable(db2); /* -------------------------------------------------*/ /* Test single record lock Transaction and read */ /* -------------------------------------------------*/ db->beginTrn(SINGLELOCK_READ_COMMITED); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); db->beginSnapshot(); BOOST_CHECK_MESSAGE(STATUS_ALREADY_INTRANSACTION == db->stat(), "Invalid beginSnapshot"); tb->setKeyNum(0); tb->seekFirst(); // lock(X) BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); // Try lock(X) tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst"); // consistent read tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); // Unlock first record. And lock(X) second record tb->seekNext(); // test unlocked first record tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->update"); // The second record, consistent read tb2->seekNext(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext"); // Try lock(X) whith lock(IX) tb2->update(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->update"); /* ---------------------------------------------------------*/ /* Test single record lock Transaction and Transaction lock */ /* ---------------------------------------------------------*/ db2->beginTrn(); // Try lock(X) tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); // Try lock(X) tb2->seekNext(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekNext"); db2->endTrn(); db->endTrn(); /* ------------------------------------------------------------*/ /* Test multi record lock Transaction and non-transaction read */ /* ------------------------------------------------------------*/ db->beginTrn(MULTILOCK_READ_COMMITED); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // lock(X) the first record tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); // Add lock(X) the second record tb->seekNext(); // No transaction user read can read allways. Use consistent_read tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); tb2->seekNext(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext"); /* --------------------------------------*/ /* Test unlock */ /* --------------------------------------*/ tb2->seekFirst(); tb2->seekNext(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekNext"); tb->unlock(); // retry seekNext. Before operation is failed but do not lost currency. tb2->seekNext(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "unlock"); tb2->seekNext(); /* --------------------------------------*/ /* Test undate record unlock */ /* --------------------------------------*/ tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->unlock();// Can not unlock updated record BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->unlock"); tb2->seekFirst(); tb2->seekNext(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "undate unlock"); /* ---------------------------------------------------------*/ /* Test multi record lock Transaction and Transaction */ /* ---------------------------------------------------------*/ db2->beginTrn(); BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn"); // Try lock(X) tb2->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst"); db2->endTrn(); db->endTrn(); /* -------------------------------------------------------------------*/ /* Test multi record lock Transaction and non-transaction record lock */ /* -------------------------------------------------------------------*/ // lock(X) non-transaction tb2->seekFirst(ROW_LOCK_X); db->beginTrn(SINGLELOCK_READ_COMMITED); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); // Try lock(X) tb->seekFirst(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst"); // Remove lock(X) tb2->seekFirst(); // Retry lock(X) tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); // update in transaction tb->setFV(fdi_name, _T("ABC")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); // move from first record. tb->seekNext(); // No transaction read can read allways. Use consistent_read tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->update(); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->update"); db->endTrn(); /* -------------------------------------------------*/ /* Test phantom read */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_READ_COMMITED); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); //read last row tb->seekLast(); //lock(X) last id = 30000 BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast"); tb->seekPrev(); //Add lock(X) BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); int last2 = tb->getFVint(fdi_id); //insert test row tb2->setFV(fdi_id, 29999); tb2->insert(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->insert stat = " << tb2->stat()); tb->seekLast(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast"); tb->seekPrev(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev"); BOOST_CHECK_MESSAGE(last2 != tb->getFVint(fdi_id), "phantom read id = " << tb->getFVint(fdi_id)); db->endTrn(); //cleanup tb2->del(); // last id = 29999 BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->del"); /* -------------------------------------------------*/ /* TAbort test */ /* -------------------------------------------------*/ db->beginTrn(SINGLELOCK_READ_COMMITED); BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn"); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->setFV(fdi_name, _T("EFG")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "update"); tb->seekNext(); db->abortTrn(); tb2->setKeyNum(0); tb2->seekFirst(); BOOST_CHECK_MESSAGE(_tcscmp(tb2->getFVstr(fdi_name), _T("ABC")) == 0, "tb->seekFirst"); /* -------------------------------------------------*/ /* Test Query and locks Single record lock */ /* -------------------------------------------------*/ db->beginTrn(SINGLELOCK_READ_COMMITED); // Test find last record locked query q; q.where(_T("id"), _T("<="), _T("100")); tb->setQuery(&q); tb->setFV(fdi_id, 1); tb->find(); while (tb->stat() == 0) tb->findNext(); BOOST_CHECK_MESSAGE(100 == tb->getFVint(fdi_id), "find last id"); // find read last is record of id = 101. // Would be difficult to identify the last // access to records at SINGLELOCK_READ_COMMITED. // No match records are unlocked. tb2->setFV(fdi_id, 100); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek stat = " << tb2->stat()); tb2->setFV(fdi_id, 101); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek stat = " << tb2->stat()); tb2->unlock(); db->endTrn(); /* -------------------------------------------------*/ /* Test Query and locks Multi record lock */ /* -------------------------------------------------*/ db->beginTrn(MULTILOCK_READ_COMMITED); // Test find records are lock. q.reset().where(_T("id"), _T("<="), 15).and_(_T("id"), _T("<>"), 13) .reject(0xFFFF); tb->setQuery(&q); tb->setFV(fdi_id, 12); tb->find(); while (tb->stat() == 0) tb->findNext(); BOOST_CHECK_MESSAGE(15 == tb->getFVint(fdi_id), "find last id"); for (int i = 12 ; i <= 16; ++i) { tb2->setFV(fdi_id, i); tb2->seek(ROW_LOCK_X); if ((i == 16)|| (i == 13)) BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek"); else BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seek"); } db->endTrn(); tb->release(); tb2->release(); database::destroy(db2); } void testRecordLock(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); table* tb2 = openTable(db2); tb->setKeyNum(0); tb2->setKeyNum(0); //Single record lock tb->seekFirst(ROW_LOCK_X); // lock(X) BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekFirst(); // Use consistent_read BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->seekFirst(ROW_LOCK_X); // Try lock(X) single BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst"); // try consistent_read. Check ended that before auto transaction tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->seekNext(ROW_LOCK_X); // lock(X) second BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->seekNext(ROW_LOCK_X); // lock(X) third second lock freed BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb->seekNext(); // nobody lock second. but REPEATABLE_READ tb2 lock all(no unlock) if (db->trxIsolationServer() == SRV_ISO_REPEATABLE_READ) BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst stat = " << tb->stat() ); else BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst stat = " << tb->stat() ); tb->seekNext(ROW_LOCK_X); // Try lock(X) third BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst"); //Update test change third with lock(X) tb2->setFV(fdi_name, _T("The 3rd")); tb2->update(); // auto trn commit and unlock all locks BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update"); tb2->seekNext(ROW_LOCK_X); // lock(X) 4th BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); tb2->setFV(fdi_name, _T("The 4th")); tb2->update(); // auto trn commit and unlock all locks // Test unlock all locks, after update tb->seekFirst(ROW_LOCK_X); // lock(X) first BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst"); tb->seekNext(ROW_LOCK_X); // lock(X) second BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext"); tb->seekNext(ROW_LOCK_X); // lock(X) third BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext"); BOOST_CHECK_MESSAGE(_tcscmp(tb->getFVstr(fdi_name), _T("The 3rd")) == 0, "tb->seekNext"); //Test Insert, After record lock operation tb->setFV(fdi_id, 21000); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->insert"); tb->setFV(fdi_id, 21000); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seek stat = " << tb->stat() ); tb->del(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->del stat = " << tb->stat() ); /* --------- Unlock test ----------------------------*/ // 1 unlock() tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->unlock(); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->unlock(); //2 auto tran ended table* tb3 = openTable(db2); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb3->seekLast(); //This operation is another table handle, then auto tran ended BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekLast"); tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->unlock(); // begin trn tb3->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekFirst"); tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst"); db2->beginTrn(); tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); db2->endTrn(); tb->unlock(); // begin snapshot tb3->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekFirst"); tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst"); db2->beginSnapshot(); tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); db2->endSnapshot(); tb->unlock(); // close Table tb->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst"); tb->release(); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->unlock(); /* --------- End Unlock test ----------------------------*/ /* --------- Invalid lock type test ----------------------------*/ tb2->seekFirst(ROW_LOCK_S); BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb2->stat(), "tb2->seekFirst"); /* --------- Invalid unlock test ----------------------------*/ tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->unlock(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->release(); tb3->release(); database::destroy(db2); } bool isMySQL5_7(database* db) { btrVersions vv; db->getBtrVersion(&vv); return (db->stat() == 0) && ((5 == vv.versions[1].majorVersion) && (7 == vv.versions[1].minorVersion)); } void testExclusive() { // db mode exclusive database* db = database::create(); /* -------------------------------------------------*/ /* database WRITE EXCLUSIVE */ /* -------------------------------------------------*/ table* tb = openTable(db, TD_OPEN_EXCLUSIVE);//DB TD_OPEN_EXCLUSIVE BOOST_CHECK_MESSAGE(0 == db->stat(), "Exclusive opened 1 "); // Can not open another connections. database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); //database open error. Check database::stat() BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat(), "open db2->stat = " << db2->stat()); dbdef* def = db->dbDef(); tabledef* td = def->tableDefs(1); td->iconIndex = 3; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef"); tb->release(); db->close(); db2->close(); /* -------------------------------------------------*/ /* database READ EXCLUSIVE */ /* -------------------------------------------------*/ tb = openTable(db, TD_OPEN_READONLY_EXCLUSIVE); // read mysql version bool MySQL5_7 = isMySQL5_7(db); // Read only open db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); BOOST_CHECK_MESSAGE(0 == db2->stat(), "read only open " << db2->stat()); db2->close(); // Normal open db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); if (MySQL5_7) BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat() , "Normal open"); else BOOST_CHECK_MESSAGE(0 == db2->stat() , "Normal open"); db2->close(); // Write Exclusive open db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_EXCLUSIVE); BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat() , "Write Exclusive open"); db2->close(); // Read Exclusive open db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_READONLY_EXCLUSIVE); BOOST_CHECK_MESSAGE(0 == db2->stat() , "Read Exclusive open"); db2->close(); tb->release(); db->close(); /* -------------------------------------------------*/ /* Nnomal and Exclusive opend tables mix use */ /* -------------------------------------------------*/ tb = openTable(db, TD_OPEN_NORMAL); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); table* tb2 = db->openTable(_T("group"), TD_OPEN_EXCLUSIVE); //Check tb2 Exclusive table* tb3 = db2->openTable(_T("group"), TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat() , "Write Exclusive open"); //if (tb2->recordCount(false) == 0) { for (int i = 1 ; i < 5 ; ++i) { tb2->setFV(fdi_id, i + 1); tb2->setFV(fdi_name, i + 1); tb2->insert(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->insert"); } } tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekLast(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast"); tb->seekLast(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast"); // Normal close first tb->close(); tb2->seekLast(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast"); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); //Reopen Normal tb = db->openTable(_T("user")); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekLast(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast"); tb->seekLast(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast"); // Exclusive close first tb2->close(); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->seekLast(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast"); /* ---------------------------------------------------*/ /* Nnomal and Exclusive opend tables mix transaction */ /* ---------------------------------------------------*/ tb2 = db->openTable(_T("group"), TD_OPEN_EXCLUSIVE); BOOST_CHECK_MESSAGE(0 == db->stat(), "open group stat = " << db->stat()) ; //Check tb2 Exclusive tb3 = db2->openTable(_T("group"), TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat() , "Write Exclusive open"); db->beginTrn(); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb->setFV(fdi_name, _T("mix trn")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->update"); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); tb2->setFV(fdi_name, _T("first mix trn tb2")); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update"); tb2->seekNext(); tb2->setFV(fdi_name, _T("second mix trn tb2")); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update"); db->endTrn(); tb2->seekFirst(); _tstring v = tb2->getFVstr(fdi_name); BOOST_CHECK_MESSAGE(v == _T("first mix trn tb2"), "check first"); tb2->seekNext(); v = tb2->getFVstr(fdi_name); BOOST_CHECK_MESSAGE(v == _T("second mix trn tb2"), "check second"); database::destroy(db); database::destroy(db2); } /* Multi database */ void testMultiDatabase(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); // not new connection BOOST_CHECK_MESSAGE(0 == db2->stat(), "db2->open"); table* tb2 = db2->openTable(_T("group")); db->beginTrn(); db2->beginTrn(); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst"); _tstring v = tb->getFVstr(fdi_name); tb->setFV(fdi_name, _T("MultiDatabase")); tb->update(); tb2->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "seekFirst"); tb2->setFV(fdi_name, _T("MultiDatabase")); tb2->update(); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "update"); db2->endTrn(); db->abortTrn(); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst"); _tstring v2 = tb->getFVstr(fdi_name); BOOST_CHECK_MESSAGE(v == v2, "check value"); tb->release(); tb2->release(); database::destroy(db2); } class worker { table* m_tb; public: worker(table* tb):m_tb(tb){} void run(){m_tb->seekLessThan(false, ROW_LOCK_X);} }; /* Getting missing value by lock wait */ void testMissingUpdate(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); BOOST_CHECK_MESSAGE(0 == db2->stat(), "db2->open"); table* tb2 = db2->openTable(_T("user")); { boost::scoped_ptr w(new worker(tb2)); // Inserting target, The InnoDB is good! tb->setFV(fdi_id, 300000); tb2->setFV(fdi_id, 300000); tb->seekLessThan(false, ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLessThan"); if (tb->stat() == 0) { tb2->seekLessThan(false, ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekLessThan"); // Get lock(X) same record in parallel. The InnoDB is good! boost::scoped_ptr t(new boost::thread(boost::bind(&worker::run, w.get()))); Sleep(100); int v = tb->getFVint(fdi_id);//v = 30000 tb->setFV(fdi_id, ++v); //v = 30001 tb->insert(); Sleep(1); t->join(); Sleep(1); if (db->trxIsolationServer() == SRV_ISO_REPEATABLE_READ) { /* When SRV_ISO_REPEATABLE_READ tb2 get gap lock first, tb can not insert, it is dedlock! */ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->insert stat= " << tb->stat()); } else { /* When SRV_ISO_READ_COMMITED, tb2 get lock after insert. But no retry loop then lock id = 30000 !!!!!!!. Oh no! This is not READ_COMMITED !. */ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLessThan stat= " << tb2->stat()); int v2 = tb2->getFVint(fdi_id); BOOST_CHECK_MESSAGE(v2 == v-1 , "value v-1 = " << v-1 << " bad = " << v2); //cleanup tb->setFV(fdi_id, v); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seek"); tb->del(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->del"); } tb2->unlock(); } // Deleting target, The InnoDB is good! tb->setFV(fdi_id, 300000); tb2->setFV(fdi_id, 300000); tb->seekLessThan(false, ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLessThan"); if (tb->stat() == 0) { // Get lock(X) same record in parallel. boost::scoped_ptr t(new boost::thread(boost::bind(&worker::run, w.get()))); Sleep(5); int v = tb->getFVint(fdi_id); tb->del(); t->join(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->insert"); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLessThan"); int v2 = tb2->getFVint(fdi_id); BOOST_CHECK_MESSAGE(v != v2 , "value v = " << v << " bad = " << v2); tb2->unlock(); } } tb->release(); tb2->release(); database::destroy(db2); } void testInsert2(database* db) { table* tb = openTable(db); int v = 40000; db->beginTrn(); tb->clearBuffer(); tb->setFV(fdi_id, v); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert"); v = 10; tb->clearBuffer(); tb->setFV((short)0, v); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual Ins"); tb->seekNext(); BOOST_CHECK_MESSAGE(11 == tb->getFVint(fdi_id), "GetEqual InsNext"); db->endTrn(); tb->release(); } void testDelete(database* db) { table* tb = openTable(db); // estimate number int count = tb->recordCount(true); bool c = (abs(count - 20003) < 5000); BOOST_CHECK_MESSAGE(c == true, "RecordCount1"); if (!c) { char tmp[256]; sprintf_s( tmp, 256, "true record count = 20003 as estimate recordCount count = %d ", count); BOOST_CHECK_MESSAGE(false, tmp); } // true number BOOST_CHECK_MESSAGE((uint_td)20003 == tb->recordCount(false), "RecordCount2"); int vv = 15001; tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seek(); BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetEqual"); tb->del(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "Delete"); tb->setFV((short)0, vv); tb->seek(); BOOST_CHECK_MESSAGE(4 == tb->stat(), "GetEqual"); // check update in key vv = 8; tb->setFV(fdi_id, vv); tb->del(table::inkey); BOOST_CHECK_MESSAGE(0 == tb->stat(), "delete changeInKey"); tb->clearBuffer(); tb->setFV(fdi_id, vv); tb->seek(); BOOST_CHECK_MESSAGE(tb->stat() == STATUS_NOT_FOUND_TI, "delete changeInKey2"); db->beginTrn(); tb->stepFirst(); while (tb->stat() == 0) { tb->del(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "Delete"); tb->stepNext(); } BOOST_CHECK_MESSAGE(9 == tb->stat(), "StepNext"); db->endTrn(); BOOST_CHECK_MESSAGE((uint_td)0 == tb->recordCount(false), "RecordCount"); tb->release(); } void testSetOwner(database* db) { table* tb = openTable(db); tb->setOwnerName(_T("ABCDEFG")); BOOST_CHECK_MESSAGE(0 == tb->stat(), "SetOwner stat = " << tb->stat()); tb->clearOwnerName(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "SetOwner stat = " << tb->stat()); tb->release(); } void testReconnect(database* db) { table* tb = openTable(db); database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true); BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect"); db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); BOOST_CHECK_MESSAGE(0 == db2->stat(), "db2->open"); table* tb2 = db2->openTable(_T("user")); //lock row tb->setFV(fdi_id, 10); tb->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seek stat = " << tb->stat()); db->disconnectForReconnectTest(); db->reconnect(); //Check restore lock tb2->setFV(fdi_id, 10); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seek stat = " << tb2->stat()); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seek stat = " << tb->stat()); BOOST_CHECK_MESSAGE(11 == tb->getFVint(fdi_id), "getFVint 11 bad = " << tb->getFVint(fdi_id)); tb2->setFV(fdi_id, 11); tb2->seek(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seek stat = " << tb2->stat()); tb->release(); tb2->release(); database::destroy(db2); } void testCreateIndex(database* db) { table* tb = openTable(db); dbdef* def = db->dbDef(); if (def) { const tabledef* td = tb->tableDef(); keydef* kd = def->insertKey(td->id, td->keyCount); kd->segments[0].fieldNum = fdi_name; //name kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segments[0].flags.bit0 = 1; // duplicatable kd->segmentCount = 1; // assign keynumber kd->keyNumber = 5; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "CreateIndex updateTableDef stat = " << def->stat()); } tb->setKeyNum(tb->tableDef()->keyCount-1); tb->createIndex(true); BOOST_CHECK_MESSAGE(0 == tb->stat(), "CreateIndex"); tb->release(); //test not mysql grant db->aclReload(); BOOST_CHECK_MESSAGE(STATUS_DB_YET_OPEN == db->stat(), "bad grantReload db->stat() = " << db->stat()); } void testDropIndex(database* db) { table* tb = openTable(db); tb->dropIndex(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "DropIndex stat = " << tb->stat()); tb->release(); } void testLogin(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; db->connect(makeUri(PROTOCOL, HOSTNAME, _T(""))); BOOST_CHECK_MESSAGE(0 == db->stat(), "connect"); if (db->stat() == 0) { // second connection database* db2 = database::create(); db2->connect(makeUri(PROTOCOL, HOSTNAME, _T("")), true); BOOST_CHECK_MESSAGE( 0 == db2->stat(), "new connection connect db->stat() = " << db->stat()); database::destroy(db2); db->disconnect(); BOOST_CHECK_MESSAGE(0 == db->stat(), "disconnect db->stat() = " << db->stat()); } // invalid host name db->connect(makeUri(PROTOCOL, _T("localhost123"), _T(""))); bool f = (db->stat() == ERROR_TD_INVALID_CLINETHOST) || (db->stat() == ERROR_TD_HOSTNAME_NOT_FOUND); BOOST_CHECK_MESSAGE(f, "bad host stat =" << db->stat()); if (!f) { #ifndef _UNICODE TCHAR buf[256]; sprintf_s(buf, 256, "bad host db->stat()=%d", db->stat()); BOOST_MESSAGE(buf); #endif } db->open(makeUri(PROTOCOL, _T("localhost123"), DBNAME, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); f = (db->stat() == ERROR_TD_INVALID_CLINETHOST) || (db->stat() == ERROR_TD_HOSTNAME_NOT_FOUND); BOOST_CHECK_MESSAGE(f, "bad host stat =" << db->stat()); testCreateNewDataBase(db); //with open db->close(); // disconnected BOOST_CHECK_MESSAGE(0 == db->stat(), "databese close db->stat() = " << db->stat()); // true database name db->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "databese connect db->stat() = " << db->stat()); if (db->stat() == 0) { db->disconnect(); BOOST_CHECK_MESSAGE(0 == db->stat(), "databese disconnect db->stat() = " << db->stat()); } // invalid database name testDropDatabase(db); db->disconnect(); BOOST_CHECK_MESSAGE(0 == db->stat(), "databese disconnect db->stat() = " << db->stat()); db->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME)); BOOST_CHECK_MESSAGE(ERROR_NO_DATABASE == db->stat(), "databese connect db->stat() = " << db->stat()); //connect is failed, no need disconnet. db->disconnect(); BOOST_CHECK_MESSAGE(1 == db->stat(), "databese disconnect db->stat() = " << db->stat()); } void testGrantReload(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, _T("mysql"), TRANSACTD_SCHEMANAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "open mysql db->stat() = " << db->stat()); db->aclReload(); BOOST_CHECK_MESSAGE(0 == db->stat(), "grantReload db->stat() = " << db->stat()); } // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ void doCreateVarTable(database* db, int id, const _TCHAR* name, char fieldType, int charset) { // create table dbdef* def = db->dbDef(); tabledef td; memset(&td, 0, sizeof(td)); td.setTableName(name); _TCHAR buf[267]; _tcscpy_s(buf, 100, name); _tcscat_s(buf, 100, _T(".dat")); td.setFileName(buf); td.id = id; td.keyCount = 0; td.fieldCount = 0; td.flags.all = 0; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; td.charsetIndex = charset; def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable"); fielddef* fd = def->insertField(id, 0); fd->setName(_T("id")); fd->type = ft_integer; fd->len = (ushort_td)4; fd = def->insertField(id, 1); fd->setName(_T("name")); fd->type = fieldType; if (fieldType == ft_mywvarchar) fd->len = (ushort_td)1 + mysql::charsize(CHARSET_UTF16LE) * 3; // max 3 char len byte else if (fieldType == ft_mywvarbinary) fd->len = (ushort_td)1 + mysql::charsize(CHARSET_UTF16LE) * 3; // max 6 char len byte else if (fieldType == ft_myvarchar) { if (charset == CHARSET_CP932) fd->len = (ushort_td)1 + mysql::charsize(CHARSET_CP932) * 3; // max 6 char len byte else if (charset == CHARSET_UTF8B4) fd->len = (ushort_td)1 + mysql::charsize(CHARSET_UTF8B4) * 3; // max 6 char len byte } else fd->len = (ushort_td)7; // max 6 char len byte fd = def->insertField(id, 2); fd->setName(_T("groupid")); fd->type = ft_integer; fd->len = (ushort_td)4; keydef* kd = def->insertKey(id, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; kd = def->insertKey(id, 1); kd->segments[0].fieldNum = 1; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segments[0].flags.bit0 = 1; // duplicateable kd->segments[0].flags.bit4 = 1; // not last segmnet kd->segments[1].fieldNum = 2; kd->segments[1].flags.bit8 = 1; // extended key type kd->segments[1].flags.bit1 = 1; // changeable kd->segments[1].flags.bit0 = 1; // duplicateable kd->segmentCount = 2; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 4"); table* tb = db->openTable(id); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); if (tb) tb->release(); } bool isUtf16leSupport(database* db) { btrVersions vv; db->getBtrVersion(&vv); if ((int)'M' == (int)vv.versions[1].type) { if (vv.versions[1].majorVersion > 5) return true; if (vv.versions[1].minorVersion > 5) return true; return false; } return true; } void testCreateDataBaseVar(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; if (db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME))) { db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "drop testvar db stat = " << db->stat()); } db->create(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "create testvar db stat = " << db->stat()); if (0 == db->stat()) { db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME), 0, 0); BOOST_CHECK_MESSAGE(0 == db->stat(), "open testvar db stat = " << db->stat()); if (0 == db->stat()) { doCreateVarTable(db, 1, _T("user1"), ft_myvarchar, CHARSET_CP932); doCreateVarTable(db, 2, _T("user2"), ft_myvarbinary, CHARSET_CP932); if (isUtf16leSupport(db)) doCreateVarTable(db, 3, _T("user3"), ft_mywvarchar, CHARSET_CP932); doCreateVarTable(db, 4, _T("user4"), ft_mywvarbinary, CHARSET_CP932); doCreateVarTable(db, 5, _T("user5"), ft_myvarchar, CHARSET_UTF8B4); db->close(); db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), TRANSACTD_SCHEMANAME), 0, 0); } } } void testDropDataBaseVar(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); if (0 == db->stat()) { db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "DropDataBaseVar"); } } void dump(const char* p, int size) { std::string s; char tmp[100]; for (int i = 0; i < size; i += 16) { for (int j = 0; j < 16; j++) { printf(tmp, "%02X ", *((unsigned char*)(p + i + j))); s.append(tmp); } s.append(" "); for (int j = 0; j < 16; j++) { printf(tmp, "%c", *((unsigned char*)(p + i + j))); s.append(tmp); } s.append("\n"); } } void doTestverField(table* tb, bool unicodeField, bool varCharField) { // Set Wide Get Wide #ifdef _WIN32 tb->setFVW(2, L"68"); #else tb->setFV(2, "68"); #endif #ifdef _WIN32 // too long string tb->setFVW(1, L"1234567"); if (varCharField) { BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"123"), "Get Set W1"); if (wstring(tb->getFVWstr(1)) != wstring(L"123")) dump((const char*)tb->getFVWstr(1), 7); } else BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"123456"), "Get Set W1"); BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 1"); // short tb->setFVW(1, L"12 "); BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"12 "), "Get Set W2"); BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 2"); // too long lanji if (unicodeField) { tb->setFVW(1, L"あいうえお\xD867\xDE3D"); // kanji that "aiueohokke" if (varCharField) BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"あいう"), "Get Set W3"); else BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"あいうえお"), "Get Set W3"); } else { tb->setFVW(1, L"0松本市"); // kanji that "matumostoshi" BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(1)) == wstring(L"0松本"), "Get Set W3"); } BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 2"); #endif // Set Ansi Get Wide // too long string tb->setFVA(1, "1234567"); if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123"), "Get Set A1"); else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123456"), "Get Set A1"); #ifdef _WIN32 BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 1"); #else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 1"); #endif // short string tb->setFVA(1, "13 "); BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("13 "), "Get Set A2"); #ifdef _WIN32 BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 2"); #else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 2"); #endif // too long lanji if (unicodeField) { #ifdef LINUX tb->setFVA(1, "あいうえお𩸽"); // kanji that "aiueohokke" if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("あいう"), "Get Set A3"); else BOOST_CHECK_MESSAGE( string(tb->getFVAstr(1)) == string("あいうえお"), "Get Set A3"); #endif } else { tb->setFVA(1, "0松本市"); // kanji that "matumostoshi" bool f = string(tb->getFVAstr(1)) == string("0松本"); BOOST_CHECK_MESSAGE(f, "Get Set A3"); if (!f) BOOST_MESSAGE(tb->getFVAstr(1)); } BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 2"); // Set Wide Get Ansi #ifdef _WIN32 // too long string tb->setFVW(1, L"1234567"); if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123"), "GetA Set W1"); else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123456"), "GetA Set W1"); BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 1"); // short string tb->setFVW(1, L"23 "); BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("23 "), "GetA Set W2"); BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 2"); // too long lanji if (unicodeField) { tb->setFVW(1, L"あいうえお\xD867\xDE3D"); // kanji that "aiueohokke" if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("あいう"), "GetA Set W3"); else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("あいうえお"), "GetA Set W3"); } else { tb->setFVW(1, L"0松本市"); // kanji that "matumostoshi" BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("0松本"), "GetA Set W3"); } BOOST_CHECK_MESSAGE(wstring(tb->getFVWstr(2)) == wstring(L"68"), "Orverrun 2"); #endif // Set Ansi Get Ansi // too long string tb->setFVA(1, "1234567"); if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123"), "GetA Set A1"); else BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("123456"), "GetA Set A1"); BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 1"); // short string tb->setFVA(1, "13 "); BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("13 "), "GetA Set A2"); BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 2"); // too long lanji if (unicodeField) { #ifdef LINUX tb->setFVA(1, "あいうえお𩸽"); // kanji that "aiueohokke" if (varCharField) BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("あいう"), "Get Set A3"); else BOOST_CHECK_MESSAGE( string(tb->getFVAstr(1)) == string("あいうえお"), "Get Set A3"); #endif } else { tb->setFVA(1, "0松本市"); // kanji that "matumostoshi" BOOST_CHECK_MESSAGE(string(tb->getFVAstr(1)) == string("0松本"), "GetA Set A3"); } BOOST_CHECK_MESSAGE(string(tb->getFVAstr(2)) == string("68"), "Orverrun 2"); } void testVarField(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open 1"); table* tb = db->openTable(_T("user1")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable"); BOOST_MESSAGE("Start acp varchar"); doTestverField(tb, false, true); tb->release(); tb = db->openTable(_T("user2")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable2"); BOOST_MESSAGE("Start acp varbinary"); doTestverField(tb, false, false); tb->release(); if (isUtf16leSupport(db)) { tb = db->openTable(_T("user3")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable3"); BOOST_MESSAGE("Start unicode varchar"); doTestverField(tb, true, true); tb->release(); } tb = db->openTable(_T("user4")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable4"); BOOST_MESSAGE("Start unicode varbinary"); doTestverField(tb, true, false); tb->release(); tb = db->openTable(_T("user5")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable5"); BOOST_MESSAGE("Start utf8 varchar"); doTestverField(tb, true, true); tb->release(); } void doVarInsert(database* db, const _TCHAR* name, unsigned int codePage, const _TCHAR* str, int start, int end, bool bulk) { _TCHAR buf[256]; table* tb = db->openTable(name); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable"); if (bulk) tb->beginBulkInsert(BULKBUFSIZE); int v; for (int i = start; i <= end; i++) { tb->clearBuffer(); tb->setFV((short)0, i); _stprintf_s(buf, 256, _T("%s%d"), str, i); tb->setFV((short)1, buf); v = i + 10; tb->setFV((short)2, v); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert"); } if (bulk) tb->commitBulkInsert(); tb->release(); } void testVarInsert(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; int start = 1; bool bulk = false; const _TCHAR* str = _T("漢字文字のテスト"); // too long kanji const _TCHAR* str2 = _T("123"); db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open 1 stat = " << db->stat()); if (0 == db->stat()) { bool utf16leSupport = isUtf16leSupport(db); doVarInsert(db, _T("user1"), CP_ACP, str, start, start, bulk); doVarInsert(db, _T("user2"), CP_ACP, str, start, start, bulk); if (utf16leSupport) doVarInsert(db, _T("user3"), CP_ACP, str, start, start, bulk); doVarInsert(db, _T("user4"), CP_ACP, str, start, start, bulk); doVarInsert(db, _T("user5"), CP_UTF8, str, start, start, bulk); ++start; doVarInsert(db, _T("user1"), CP_ACP, str2, start, start, bulk); doVarInsert(db, _T("user2"), CP_ACP, str2, start, start, bulk); if (utf16leSupport) doVarInsert(db, _T("user3"), CP_ACP, str2, start, start, bulk); doVarInsert(db, _T("user4"), CP_ACP, str2, start, start, bulk); doVarInsert(db, _T("user5"), CP_UTF8, str2, start, start, bulk); ++start; bulk = true; int end = 1000; doVarInsert(db, _T("user1"), CP_ACP, _T(""), start, end, bulk); doVarInsert(db, _T("user2"), CP_ACP, _T(""), start, end, bulk); if (utf16leSupport) doVarInsert(db, _T("user3"), CP_ACP, _T(""), start, end, bulk); doVarInsert(db, _T("user4"), CP_ACP, _T(""), start, end, bulk); doVarInsert(db, _T("user5"), CP_UTF8, _T(""), start, end, bulk); } } void doVarRead(database* db, const _TCHAR* name, unsigned int codePage, const _TCHAR* str, int num, char_td key) { table* tb = db->openTable(name); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); tb->clearBuffer(); tb->setKeyNum(key); if (key == 0) tb->setFV((short)0, num); else { int v = num + 10; tb->setFV((short)1, str); tb->setFV((short)2, v); } tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetEqual var stat"); // test read of var field bool f = _tstring(str) == _tstring(tb->getFVstr(1)); BOOST_CHECK_MESSAGE(f, "GetEqual var field1"); // test read of second field BOOST_CHECK_MESSAGE((int)(num + 10) == tb->getFVint(2), "GetEqual var field2"); tb->release(); } void testVarRead(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; const _TCHAR* str = _T("漢字文"); const _TCHAR* str3 = _T("漢字文字のテ"); const _TCHAR* str2 = _T("123"); const _TCHAR* str4 = _T("1232"); db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); if (0 == db->stat()) { bool utf16leSupport = isUtf16leSupport(db); int num = 1; char_td key = 0; // too long string doVarRead(db, _T("user1"), CP_ACP, str, num, key); doVarRead(db, _T("user2"), CP_ACP, str, num, key); if (utf16leSupport) doVarRead(db, _T("user3"), CP_ACP, str, num, key); doVarRead(db, _T("user4"), CP_ACP, str3, num, key); doVarRead(db, _T("user5"), CP_UTF8, str, num, key); // short string ++num; doVarRead(db, _T("user1"), CP_ACP, str2, num, key); doVarRead(db, _T("user2"), CP_ACP, str4, num, key); if (utf16leSupport) doVarRead(db, _T("user3"), CP_ACP, str2, num, key); doVarRead(db, _T("user4"), CP_ACP, str4, num, key); doVarRead(db, _T("user5"), CP_UTF8, str2, num, key); key = 1; doVarRead(db, _T("user1"), CP_ACP, _T("120"), 120, key); doVarRead(db, _T("user2"), CP_ACP, _T("120"), 120, key); if (utf16leSupport) doVarRead(db, _T("user3"), CP_ACP, _T("120"), 120, key); doVarRead(db, _T("user4"), CP_ACP, _T("120"), 120, key); doVarRead(db, _T("user5"), CP_UTF8, _T("120"), 120, key); } } void doVarFilter(database* db, const _TCHAR* name, unsigned int codePage, const _TCHAR* str, int num, char_td key) { table* tb = db->openTable(name); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); tb->clearBuffer(); tb->setKeyNum(key); if (key == 0) { _TCHAR buf[120]; _stprintf_s(buf, 120, _T("id > %d and id <= %d"), num, num + 10); tb->setFilter(buf, 0, 10); // find forword tb->setFV((short)0, num); tb->seekGreater(true); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetGreater var stat"); for (int i = num + 1; i <= num + 10; i++) { tb->findNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetGreater var stat"); // test read of var field BOOST_CHECK_MESSAGE(i == tb->getFVint(1), "findNext"); // test read of second field BOOST_CHECK_MESSAGE((int)(i + 10) == tb->getFVint(2), "GetEqual var field2"); } // find previous int v = num + 10; tb->setFilter(buf, 0, 10); tb->setFV(fdi_id, v); tb->seekLessThan(true); BOOST_CHECK_MESSAGE(0 == tb->stat(), "GetPrevious var stat"); BOOST_CHECK_MESSAGE(v == tb->getFVint(fdi_id), "GetPrevious"); for (int i = num + 10; i > num; i--) { tb->findPrev(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "FindPrev var stat"); // test read of var field BOOST_CHECK_MESSAGE(i == tb->getFVint(1), "FindPrev"); // test read of second field BOOST_CHECK_MESSAGE((int)(i + 10) == tb->getFVint(2), "FindPrev var field2"); } // test record count BOOST_CHECK_MESSAGE((uint_td)10 == tb->recordCount(), "GetEqual var field2"); } else { int v = num + 10; tb->setFV((short)1, str); tb->setFV((short)2, v); } tb->release(); } void testFilterVar(database* db) { if (_tcscmp(PROTOCOL, _T("tdap")) != 0) return; db->open(makeUri(PROTOCOL, HOSTNAME, _T("testvar"), BDFNAME)); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); if (0 == db->stat()) { const _TCHAR* str = _T("漢字文"); const _TCHAR* str3 = _T("漢字文字のテ"); bool utf16leSupport = isUtf16leSupport(db); int num = 10; char_td key = 0; doVarFilter(db, _T("user1"), CP_ACP, str, num, key); doVarFilter(db, _T("user2"), CP_ACP, str, num, key); if (utf16leSupport) doVarFilter(db, _T("user3"), CP_ACP, str, num, key); doVarFilter(db, _T("user4"), CP_ACP, str3, num, key); doVarFilter(db, _T("user5"), CP_UTF8, str, num, key); #ifdef _UNICODE // short string const _TCHAR* str2 = _T("123"); const _TCHAR* str4 = _T("1232"); ++num; doVarFilter(db, L"user1", CP_ACP, str2, num, key); doVarFilter(db, L"user2", CP_ACP, str4, num, key); if (utf16leSupport) doVarFilter(db, L"user3", CP_ACP, str2, num, key); doVarFilter(db, L"user4", CP_ACP, str4, num, key); doVarFilter(db, L"user5", CP_UTF8, str2, num, key); #endif key = 1; doVarFilter(db, _T("user1"), CP_ACP, _T("120"), 120, key); doVarFilter(db, _T("user2"), CP_ACP, _T("120"), 120, key); if (utf16leSupport) doVarFilter(db, _T("user3"), CP_ACP, _T("120"), 120, key); doVarFilter(db, _T("user4"), CP_ACP, _T("120"), 120, key); doVarFilter(db, _T("user5"), CP_UTF8, _T("120"), 120, key); } } // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ void stringFileterCreateTable(database* db, int id, const _TCHAR* name, uchar_td type, uchar_td type2) { // create table dbdef* def = db->dbDef(); tabledef td; memset(&td, 0, sizeof(td)); td.setTableName(name); _TCHAR buf[267]; _tcscpy_s(buf, 100, name); _tcscat_s(buf, 100, _T(".dat")); td.setFileName(buf); td.id = id; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; td.charsetIndex = CHARSET_UTF8B4; // td.charsetIndex = CHARSET_CP932; def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable stat = " << def->stat()); fielddef* fd = def->insertField(id, 0); fd->setName(_T("id")); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 1 stat = " << def->stat()); fd = def->insertField(id, 1); fd->setName(_T("name")); fd->type = type; fd->len = 44; if (fd->varLenBytes()) { fd->len = fd->varLenBytes() + 44; fd->keylen = fd->len; } if (fd->blobLenBytes()) { fd->len = 12; // 8+4 } fd->keylen = fd->len; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); fd = def->insertField(id, 2); fd->setName(_T("namew")); fd->type = type2; fd->len = 44; if (fd->varLenBytes()) { fd->len = fd->varLenBytes() + 44; fd->keylen = fd->len; } if (fd->blobLenBytes()) { fd->len = 12; // 8+4 } fd->keylen = fd->len; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 3"); keydef* kd = def->insertKey(id, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 4"); kd = def->insertKey(id, 1); kd->segments[0].fieldNum = 1; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segments[0].flags.bit0 = 1; // duplicateable kd->segmentCount = 1; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 5"); kd = def->insertKey(id, 2); kd->segments[0].fieldNum = 2; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segments[0].flags.bit0 = 1; // duplicateable kd->segmentCount = 1; def->updateTableDef(id); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 6"); } void doInsertStringFileter(table* tb) { tb->clearBuffer(); int id = 1; tb->setFV(_T("id"), id); tb->setFV(_T("name"), _T("あいうえおかきくこ")); tb->setFV(_T("namew"), _T("あいうえおかきくこ")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 1"); tb->clearBuffer(); id = 2; tb->setFV(_T("id"), id); tb->setFV(_T("name"), _T("A123456")); tb->setFV(_T("namew"), _T("A123456")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 2"); tb->beginBulkInsert(BULKBUFSIZE); tb->clearBuffer(); id = 3; tb->setFV(_T("id"), id); tb->setFV(_T("name"), _T("あいがあればOKです")); tb->setFV(_T("namew"), _T("あいがあればOKです")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 3"); tb->clearBuffer(); id = 4; tb->setFV(_T("id"), id); tb->setFV(_T("name"), _T("おはようございます")); tb->setFV(_T("namew"), _T("おはようございます")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 3"); tb->clearBuffer(); id = 5; tb->setFV(_T("id"), id); tb->setFV(_T("name"), _T("おめでとうございます。")); tb->setFV(_T("namew"), _T("おめでとうございます。")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 4"); tb->commitBulkInsert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "InsertStringFileter 5"); } void doTestReadSF(table* tb) { tb->setKeyNum(0); tb->clearBuffer(); int id = 1; tb->setFV(_T("id"), id); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("あいうえおかきくこ")) == _tstring(tb->getFVstr(1)), "doTestReadSF2"); BOOST_CHECK_MESSAGE(_tstring(_T("あいうえおかきくこ")) == _tstring(tb->getFVstr(1)), "doTestReadSF2b"); id = 3; tb->setFV(_T("id"), id); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF3"); BOOST_CHECK_MESSAGE(_tstring(_T("あいがあればOKです")) == _tstring(tb->getFVstr(1)), "doTestReadSF4"); BOOST_CHECK_MESSAGE(_tstring(_T("あいがあればOKです")) == _tstring(tb->getFVstr(2)), "doTestReadSF4b"); tb->setKeyNum(1); tb->clearBuffer(); tb->setFV(_T("name"), _T("A123456")); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF5"); BOOST_CHECK_MESSAGE(_tstring(_T("A123456")) == _tstring(tb->getFVstr(1)), "doTestReadSF6"); tb->setKeyNum(2); tb->clearBuffer(); tb->setFV(_T("namew"), _T("A123456")); tb->seek(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF5"); BOOST_CHECK_MESSAGE(_tstring(_T("A123456")) == _tstring(tb->getFVstr(2)), "doTestReadSF6"); } void doTestSF(table* tb) { tb->setKeyNum(0); tb->clearBuffer(); tb->setFilter(_T("name = 'あい*'"), 0, 10); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); /* If this point segmentation fult. Then drop database teststring. */ tb->findNext(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("あいうえおかきくこ")) == _tstring(tb->getFVstr(1)), "doTestReadSF2"); BOOST_CHECK_MESSAGE(2 == (int)tb->recordCount(), "doTestReadSF2"); tb->setFilter(_T("name <> 'あい*'"), 0, 10); BOOST_CHECK_MESSAGE(3 == (int)tb->recordCount(), "doTestReadSF2"); tb->clearBuffer(); tb->setFilter(_T("name <> 'あい*'"), 0, 10); tb->seekFirst(); tb->findNext(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1 stat = " << tb->stat()); BOOST_CHECK_MESSAGE(_tstring(_T("A123456")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("おはようございます")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("おめでとうございます。")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findNext(); BOOST_CHECK_MESSAGE(9 == tb->stat(), "doTestReadSF1"); tb->clearBuffer(); tb->seekLast(); tb->findPrev(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("おめでとうございます。")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findPrev(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("おはようございます")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findPrev(false); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1"); BOOST_CHECK_MESSAGE(_tstring(_T("A123456")) == _tstring(tb->getFVstr(2)), "doTestReadSF1"); tb->findPrev(); BOOST_CHECK_MESSAGE(9 == tb->stat(), "doTestReadSF1"); tb->setFilter(_T("name = 'あい'"), 0, 10); BOOST_CHECK_MESSAGE(0 == (int)tb->recordCount(), "doTestReadSF2"); tb->setFilter(_T("name <> ''"), 0, 10); BOOST_CHECK_MESSAGE(5 == (int)tb->recordCount(), "doTestReadSF2"); // test setFilter don't change field value tb->clearBuffer(); tb->setFV(_T("name"), _T("ABCDE")); tb->setFilter(_T("name = 'あい'"), 0, 10); BOOST_CHECK_MESSAGE(_tstring(_T("ABCDE")) == _tstring(tb->getFVstr(1)), "doTestReadSF2 field value"); } void doTestUpdateSF(table* tb) { tb->setKeyNum(0); tb->clearBuffer(); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); tb->setFV(_T("name"), _T("ABCDE")); tb->setFV(_T("namew"), _T("ABCDEW")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); tb->setFV(_T("name"), _T("ABCDE2")); tb->setFV(_T("namew"), _T("ABCDEW2")); tb->update(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); BOOST_CHECK_MESSAGE(_tstring(_T("ABCDE")) == _tstring(tb->getFVstr(1)), "doTestUpdateSF"); BOOST_CHECK_MESSAGE(_tstring(_T("ABCDEW")) == _tstring(tb->getFVstr(2)), "doTestUpdateSF"); tb->seekNext(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestUpdateSF stat = " << tb->stat()); BOOST_CHECK_MESSAGE(_tstring(_T("ABCDE2")) == _tstring(tb->getFVstr(1)), "doTestUpdateSF"); BOOST_CHECK_MESSAGE(_tstring(_T("ABCDEW2")) == _tstring(tb->getFVstr(2)), "doTestUpdateSF"); } void doTestStringFileter(database* db, int id, const _TCHAR* name, uchar_td type, uchar_td type2) { stringFileterCreateTable(db, id, name, type, type2); table* tb = db->openTable(id); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable"); doInsertStringFileter(tb); doTestReadSF(tb); doTestSF(tb); doTestUpdateSF(tb); tb->release(); } void testDropDataBaseStr(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME), 0, 0); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "DropDataBaseTestString stat=" << db->stat()); } void testStringFileter(database* db) { db->create(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME)); if (db->stat() == STATUS_TABLE_EXISTS_ERROR) { testDropDataBaseStr(db); db->create(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME)); } BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase"); db->open(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME), 0, 0); BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase 1 stat = " << db->stat()); doTestStringFileter(db, 1, _T("zstring"), ft_zstring, ft_wzstring); if (isUtf16leSupport(db)) doTestStringFileter(db, 2, _T("myvarchar"), ft_myvarchar, ft_mywvarchar); else doTestStringFileter(db, 2, _T("myvarchar"), ft_myvarchar, ft_myvarchar); doTestStringFileter(db, 3, _T("mytext"), ft_mytext, ft_myblob); db->close(); } // ------------------------------------------------------------------------ _TCHAR dbNmae[50] = { _T("テスト") }; _TCHAR bdfNmae[50] = { _T("構成.bdf") }; _TCHAR tableNmae[50] = { _T("漢字テーブル") }; _TCHAR fdName1[50] = { _T("番号") }; _TCHAR fdName2[50] = { _T("名前") }; bool nameInited = false; void initKanjiName() { #if (!defined(_UNICODE) && defined(_WIN32)) if (!nameInited) { wchar_t tmp[50]; MultiByteToWideChar(932, MB_PRECOMPOSED, dbNmae, -1, tmp, 50); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, dbNmae, 50, NULL, NULL); MultiByteToWideChar(932, MB_PRECOMPOSED, bdfNmae, -1, tmp, 50); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, bdfNmae, 50, NULL, NULL); MultiByteToWideChar(932, MB_PRECOMPOSED, tableNmae, -1, tmp, 50); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, tableNmae, 50, NULL, NULL); MultiByteToWideChar(932, MB_PRECOMPOSED, fdName1, -1, tmp, 50); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, fdName1, 50, NULL, NULL); MultiByteToWideChar(932, MB_PRECOMPOSED, fdName2, -1, tmp, 50); WideCharToMultiByte(CP_UTF8, 0, tmp, -1, fdName2, 50, NULL, NULL); nameInited = true; } #endif } void testDropDatabaseKanji(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, dbNmae, bdfNmae)); BOOST_CHECK_MESSAGE(0 == db->stat(), "db->open stat = " << db->stat()); db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "db->drop() stat = " << db->stat()); } void testKnajiCreateSchema(database* db) { initKanjiName(); db->create(makeUri(PROTOCOL, HOSTNAME, dbNmae, bdfNmae)); if (db->stat() == STATUS_TABLE_EXISTS_ERROR) { testDropDatabaseKanji(db); db->create(makeUri(PROTOCOL, HOSTNAME, dbNmae, bdfNmae)); } BOOST_CHECK_MESSAGE(0 == db->stat(), "createKanjiDatabase stat = " << db->stat()); // create table db->open(makeUri(PROTOCOL, HOSTNAME, dbNmae, bdfNmae), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "createKanjiDatabase 1 stat = " << db->stat()); dbdef* def = db->dbDef(); if (def) { tabledef td; memset(&td, 0, sizeof(tabledef)); #ifndef _UNICODE td.schemaCodePage = CP_UTF8; td.charsetIndex = CHARSET_UTF8; #else td.schemaCodePage = CP_UTF8; td.charsetIndex = CHARSET_CP932; #endif td.setTableName(tableNmae); td.setFileName(tableNmae); td.id = 1; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable stat = " << def->stat()); fielddef* fd = def->insertField(1, 0); fd->setName(fdName1); fd->type = ft_integer; fd->len = (ushort_td)4; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 1 stat = " << def->stat()); fd = def->insertField(1, 1); fd->setName(fdName2); fd->type = ft_zstring; fd->len = (ushort_td)33; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 2 stat = " << def->stat()); keydef* kd = def->insertKey(1, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 3 stat = " << def->stat()); } } table* openKnajiTable(database* db) { db->open(makeUri(PROTOCOL, HOSTNAME, dbNmae, bdfNmae), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "openKnajiTable 1 stat = " << db->stat()); table* tb = db->openTable(tableNmae); BOOST_CHECK_MESSAGE(0 == db->stat(), "openKnajiTable 2 stat = " << db->stat()); return tb; } void testInsertKanji(database* db) { table* tb = openKnajiTable(db); tb->clearBuffer(); tb->setFV(fdName1, _T("1")); tb->setFV(fdName2, _T("小坂")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert 1"); tb->clearBuffer(); tb->setFV(fdName1, _T("2")); tb->setFV(fdName2, _T("矢口")); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert 2"); tb->release(); } void testGetEqualKanji(database* db) { table* tb = openKnajiTable(db); tb->clearBuffer(); tb->setFV((short)0, 1); tb->seek(); BOOST_CHECK_MESSAGE(1 == tb->getFVint(fdName1), "GetEqual id 1"); BOOST_CHECK_MESSAGE(_tcscmp(tb->getFVstr(fdName2), _T("小坂")) == 0, "GetEqual name 2"); tb->setFV((short)0, 2); tb->seek(); BOOST_CHECK_MESSAGE(2 == tb->getFVint(fdName1), "GetEqual id 2"); BOOST_CHECK_MESSAGE(_tcscmp(tb->getFVstr(fdName2), _T("矢口")) == 0, "GetEqual name 2"); tb->release(); } // ------------------------------------------------------------------------ void testResultField(database* db) { table* tb = openTable(db); resultField rf; rf.setParam(tb, _T("name")); BOOST_CHECK_MESSAGE(rf.len == 33, " resultField.setParam"); BOOST_CHECK_MESSAGE(rf.pos == 4, " resultField.setParam"); size_t len = rf.size(); BOOST_CHECK_MESSAGE(len == 4, " resultField.writeBuffer"); tb->release(); } void testResultDef() { resultDef rd; rd.reset(); BOOST_CHECK_MESSAGE(rd.maxRows == 0, " resultDef.maxRows"); BOOST_CHECK_MESSAGE(rd.fieldCount == 0, " resultDef.fieldCount"); size_t len = rd.size(); BOOST_CHECK_MESSAGE(len == 4, " resultDef.writeBuffer"); } void testLogic(database* db) { table* tb = openTable(db); logic lc; lc.setParam(tb, _T("name"), _T("="), _T("abc"), eCend); BOOST_CHECK_MESSAGE(lc.type == ft_zstring, " logic.type"); BOOST_CHECK_MESSAGE(lc.len == 33, " logic.len"); BOOST_CHECK_MESSAGE(lc.pos == 4, " logic.pos"); BOOST_CHECK_MESSAGE(lc.logType == 1, " logic.logType"); BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr"); BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "abc") == 0, " logic.data"); int len = lc.size(); BOOST_CHECK_MESSAGE(len == 7 + 33, " logic.writeBuffer"); // compField invalid filed name bool ret = lc.setParam(tb, _T("name"), _T("="), _T("1"), eCend, true); BOOST_CHECK_MESSAGE(ret == false, " logic invalid filed name"); // compField ret = lc.setParam(tb, _T("name"), _T("="), _T("id"), eCend, true); BOOST_CHECK_MESSAGE(ret == true, " logic filed name"); BOOST_CHECK_MESSAGE(lc.type == ft_zstring, " logic.type"); BOOST_CHECK_MESSAGE(lc.len == 33, " logic.len"); BOOST_CHECK_MESSAGE(lc.pos == 4, " logic.pos"); BOOST_CHECK_MESSAGE(lc.logType == 1 + CMPLOGICAL_FIELD, " logic.logType compField"); BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr"); BOOST_CHECK_MESSAGE(*((short*)lc.data) == 0, " logic.data"); len = lc.size(); BOOST_CHECK_MESSAGE(len == 7 + 2, " logic.writeBuffer"); // invalid filed name ret = lc.setParam(tb, _T("name1"), _T("="), _T("id"), eCend, true); BOOST_CHECK_MESSAGE(ret == false, " logic invalid filed name2"); // wildcard lc.setParam(tb, _T("name"), _T("="), _T("abc*"), eCend, false); BOOST_CHECK_MESSAGE(lc.type == ft_zstring, " logic.type"); BOOST_CHECK_MESSAGE(lc.len == 3, " logic.len"); BOOST_CHECK_MESSAGE(lc.pos == 4, " logic.pos"); BOOST_CHECK_MESSAGE(lc.logType == 1, " logic.logType"); BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr"); BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "abc") == 0, " logic.data"); len = lc.size(); BOOST_CHECK_MESSAGE(len == 7 + 3, " logic.writeBuffer"); lc.setParam(tb, _T("name"), _T("="), _T("漢字*"), eCend, false); BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "漢字") == 0, " logic.data"); len = lc.size(); BOOST_CHECK_MESSAGE(len == (int)(7 + (_tcslen(_T("漢字")) * sizeof(_TCHAR))), " logic.writeBuffer len =" << len); // combine lc.setParam(tb, _T("name"), _T("="), _T("abc*"), eCor, false); BOOST_CHECK_MESSAGE(lc.opr == 2, " logic.opr or"); lc.setParam(tb, _T("name"), _T("="), _T("abc*"), eCand, false); BOOST_CHECK_MESSAGE(lc.opr == 1, " logic.opr and"); // logType ret = lc.setParam(tb, _T("name"), _T("!="), _T("abc*"), eCend, false); BOOST_CHECK_MESSAGE(lc.logType == 255, " logic.logType !="); BOOST_CHECK_MESSAGE(ret == false, " logic invalid logType"); // canJoin // zstring is cannot join lc.setParam(tb, _T("name"), _T("="), _T("1"), eCand, false); BOOST_CHECK_MESSAGE(lc.canJoin(false) == false, " logic canJoin"); BOOST_CHECK_MESSAGE(lc.canJoin(true) == false, " logic canJoin"); lc.setParam(tb, _T("id"), _T("="), _T("1"), eCand, false); BOOST_CHECK_MESSAGE(lc.canJoin(false) == true, " logic canJoin"); BOOST_CHECK_MESSAGE(lc.canJoin(true) == true, " logic canJoin"); lc.opr = eCend; BOOST_CHECK_MESSAGE(lc.canJoin(true) == false, " logic canJoin"); BOOST_CHECK_MESSAGE(lc.canJoin(false) == true, " logic canJoin"); lc.opr = eCor; BOOST_CHECK_MESSAGE(lc.canJoin(true) == false, " logic canJoin"); BOOST_CHECK_MESSAGE(lc.canJoin(false) == true, " logic canJoin"); lc.opr = eCand; logic lc2; lc2.setParam(tb, _T("id"), _T("="), _T("1"), eCend, false); lc2.pos = 3; lc.isNextFiled(&lc2); BOOST_CHECK_MESSAGE(lc.isNextFiled(&lc2) == false, " logic isNextFiled"); lc2.pos = 4; BOOST_CHECK_MESSAGE(lc.isNextFiled(&lc2) == true, " logic isNextFiled"); // join lc.joinAfter(&lc2); BOOST_CHECK_MESSAGE(lc.len == 8, " logic joinAfter"); BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic joinAfter"); // placeHolder lc.setParam(tb, _T("name"), _T("="), _T("?"), eCand); BOOST_CHECK_MESSAGE(lc.placeHolder == true, " logic placeHolder"); lc.setValue(tb, _T("abc*")); BOOST_CHECK_MESSAGE(strcmp((const char*)lc.data, "abc") == 0, "logic setValue"); BOOST_CHECK_MESSAGE(lc.len == 3, "logic setValue"); header hd; len = hd.size(); BOOST_CHECK_MESSAGE(len == 8, " header.writeBuffer"); tb->release(); } void testQuery() { queryBase q; q.queryString(_T("id = 0 and name = 'Abc efg'")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("id = '0' and name = 'Abc efg'"), "queryString"); q.queryString(_T("")); q.addLogic(_T("id"), _T("="), _T("0")); q.addLogic(_T("and"), _T("name"), _T("="), _T("Abc efg")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("id = '0' and name = 'Abc efg'"), "queryString"); q.queryString(_T("select id,name id = 0 AND name = 'Abc&' efg'")); BOOST_CHECK_MESSAGE( _tstring(q.toString()) == _T("select id,name id = '0' AND name = 'Abc&' efg'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addLogic(_T("id"), _T("="), _T("0")); q.addLogic(_T("AND"), _T("name"), _T("="), _T("Abc' efg")); BOOST_CHECK_MESSAGE( _tstring(q.toString()) == _T("select id,name id = '0' AND name = 'Abc&' efg'"), "queryString"); q.queryString(_T("select id,name id = 0 AND name = 'Abc&& efg'")); BOOST_CHECK_MESSAGE( _tstring(q.toString()) == _T("select id,name id = '0' AND name = 'Abc&& efg'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addLogic(_T("id"), _T("="), _T("0")); q.addLogic(_T("AND"), _T("name"), _T("="), _T("Abc& efg")); BOOST_CHECK_MESSAGE( _tstring(q.toString()) == _T("select id,name id = '0' AND name = 'Abc&& efg'"), "queryString"); q.queryString(_T("*")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("*"), "queryString"); q.queryString(_T("")); q.all(); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("*"), "queryString"); q.queryString(_T("Select id,name id = 2")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name id = '2'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addLogic(_T("id"), _T("="), _T("2")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name id = '2'"), "queryString"); q.queryString(_T("SELECT id,name,fc id = 2")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc id = '2'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addField(_T("fc")); q.addLogic(_T("id"), _T("="), _T("2")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc id = '2'"), "queryString"); q.queryString(_T("select id,name,fc id = 2 and name = '3'")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc id = '2' and name = '3'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addField(_T("fc")); q.addLogic(_T("id"), _T("="), _T("2")); q.addLogic(_T("and"), _T("name"), _T("="), _T("3")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc id = '2' and name = '3'"), "queryString"); // IN include q.queryString(_T("select id,name,fc IN '1','2','3'")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc in '1','2','3'"), "queryString"); q.queryString(_T("")); q.addField(_T("id")); q.addField(_T("name")); q.addField(_T("fc")); q.addSeekKeyValue(_T("1")); q.addSeekKeyValue(_T("2")); q.addSeekKeyValue(_T("3")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select id,name,fc in '1','2','3'"), "queryString"); q.queryString(_T("IN '1','2','3'")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("in '1','2','3'"), "queryString"); q.queryString(_T("IN 1,2,3")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("in '1','2','3'"), "queryString"); q.queryString(_T("")); q.addSeekKeyValue(_T("1")); q.addSeekKeyValue(_T("2")); q.addSeekKeyValue(_T("3")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("in '1','2','3'"), "queryString"); // special field name q.queryString(_T("select = 1")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select = '1'"), "queryString"); q.queryString(_T("")); q.addLogic(_T("select"), _T("="), _T("1")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("select = '1'"), "queryString"); q.queryString(_T("in <> 1")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("in <> '1'"), "queryString"); q.queryString(_T("")); q.addLogic(_T("in"), _T("<>"), _T("1")); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("in <> '1'"), "queryString"); // test auto_escape q.queryString(_T("code = ab'c"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'ab&'c'"), "queryString"); q.queryString(_T("code = ab&c"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'ab&&c'"), "queryString"); q.queryString(_T("code = abc&"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&&'"), "queryString"); q.queryString(_T("code = abc&&"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&&&&'"), "queryString"); q.queryString(_T("code = 'abc&'"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&&'"), "queryString"); q.queryString(_T("code = 'abc&&'"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&&&&'"), "queryString"); q.queryString(_T("code = 'ab'c'"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'ab&'c'"), "queryString"); q.queryString(_T("code = 'abc''"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&''"), "queryString"); q.queryString(_T("code = abc'"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc&''"), "queryString"); // Invalid end no close ' q.queryString(_T("code = 'abc"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = 'abc'"), "queryString"); q.queryString(_T("code = &abc"), true); BOOST_CHECK_MESSAGE(_tstring(q.toString()) == _T("code = '&&abc'"), "queryString"); } void teetNewDelete(database* db) { // printf("new delete start \n"); for (int i = 0; i < 500; ++i) { queryBase qb; qb.reset(); query q; q.reset(); recordsetQuery rq; rq.reset(); groupQuery gq; gq.reset(); fieldNames f; f.addValue(_T("abc")); activeTable atu(db, _T("user")); atu.index(0); activeTable atg(db, _T("groups")); atg.index(0); fieldNames fns; fns.keyField(_T("a")); client::sum s(fns); s.reset(); client::count c(_T("a")); c.reset(); client::avg a(fns); a.reset(); client::min mi(fns); mi.reset(); client::max ma(fns); ma.reset(); recordset rs; rs.clear(); #ifndef BCB_64 queryBase* nqb1 = new queryBase(); // bcb64 bad delete nqb1; #endif queryBase* nqb = queryBase::create(); // All OK nqb->release(); query* nqq = query::create(); // All OK nqq->release(); #ifndef BCB_64 query* nqq1 = new query(); // bcb64 bad delete nqq1; #endif recordsetQuery* nrq = recordsetQuery::create(); // All OK nrq->release(); #ifndef BCB_64 recordsetQuery* nrqq = new recordsetQuery(); // bcb64 bad delete nrqq; groupQuery* ngq1 = new groupQuery(); // bcb64 bad delete ngq1; #endif groupQuery* ngq = groupQuery::create(); // All OK ngq->release(); fieldNames* nfn = fieldNames::create(); // All OK nfn->release(); #ifndef BCB_64 fieldNames* nfn1 = new fieldNames(); // bcb64 bad delete nfn1; #endif activeTable* at = new activeTable(db, _T("user")); // All OK activeTable* atg1 = new activeTable(db, _T("groups")); // All OK delete atg1; delete at; #ifndef BCB_64 client::sum* ns1 = new sum(fns); // bcb64 bad delete ns1; client::count* nc1 = new client::count(_T("a")); // bcb64 bad delete nc1; client::avg* na1 = new client::avg(fns); // bcb64 bad delete na1; client::min* nmin1 = new client::min(fns); // bcb64 bad delete nmin1; client::max* nmax1 = new client::max(fns); // bcb64 bad delete nmax1; #endif client::sum* ns = sum::create(fns); // All OK ns->release(); client::count* nc = client::count::create(_T("a")); // All OK nc->release(); client::avg* na = client::avg::create(fns); // All OK na->release(); client::min* nmin = client::min::create(fns); // All OK nmin->release(); client::max* nmax = client::max::create(fns); // All OK nmax->release(); recordset* r = new recordset(); // All OK recordset* rc(r->clone()); // All OK // delete rc; //All bad rc->release(); delete r; // All OK } //activeTable releaseTable activeTable* at = new activeTable(db, _T("user")); at->releaseTable(); BOOST_CHECK_MESSAGE(at->table() == NULL, " activeTable::releaseTable"); delete at; } void testRecordsetClone(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); //activeTable atg(db, _T("groups")); activeTable ate(db, _T("extention")); recordset* rs = recordset::create(); query q; atu.alias(fd_name, _T("name")); q.select(_T("id"), _T("name"), _T("group")) .where(_T("id"), _T("<="), 15000); atu.index(0).keyValue(1).read(*rs, q); BOOST_CHECK_MESSAGE(rs->size() == 15000, " rs.size() 15000 bad = " << rs->size()); BOOST_CHECK_MESSAGE(rs->fieldDefs()->size() == 3, " rs.fieldDefs()->size() 3 bad = " << rs->fieldDefs()->size()); // Join extention::comment q.reset(); ate.index(0).join( *rs, q.select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany), _T("id")); BOOST_CHECK_MESSAGE(rs->size() == 15000, "join rs.size() 15000 bad = " << rs->size()); BOOST_CHECK_MESSAGE(rs->fieldDefs()->size() == 4, " rs.fieldDefs()->size() 4 bad = " << rs->fieldDefs()->size()); recordset* rs2 = rs->clone(); rs->release(); rs2->release(); } void testJoin(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); activeTable atg(db, _T("groups")); activeTable ate(db, _T("extention")); recordset rs; query q; atu.alias(fd_name, _T("name")); q.select(_T("id"), _T("name"), _T("group")) .where(_T("id"), _T("<="), 15000); atu.index(0).keyValue(1).read(rs, q); BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size() 15000 bad = " << rs.size()); BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 3, " rs.fieldDefs()->size() 3 bad = " << rs.fieldDefs()->size()); // Join extention::comment q.reset(); ate.index(0).join( rs, q.select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany), _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size() 15000 bad = " << rs.size()); BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 4, " rs.fieldDefs()->size() 4 bad = " << rs.fieldDefs()->size()); // test reverse row& last = rs.reverse().first(); BOOST_CHECK_MESSAGE(last[_T("id")].i() == 15000, "last field id == 15000"); BOOST_CHECK_MESSAGE(_tstring(last[_T("comment")].c_str()) == _tstring(_T("15000 comment")), "last field comment"); // Join group::name q.reset(); atg.alias(_T("name"), _T("group_name")); atg.index(0).join(rs, q.select(_T("group_name")), _T("group")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000"); row& first = rs.last(); BOOST_CHECK_MESSAGE(first[_T("id")].i() == 1, "first field id == 1"); BOOST_CHECK_MESSAGE(_tstring(first[_T("comment")].c_str()) == _tstring(_T("1 comment")), "first field comment"); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); // row_ptr row = rs[15000 - 9]; row& rec = rs[15000 - 9]; BOOST_CHECK_MESSAGE( _tstring(rec[_T("group_name")].c_str()) == _tstring(_T("4 group")), "group_name = 4 group " << string((rec)[_T("group_name")].a_str())); // Test orderby rs.orderBy(_T("group_name")); // rec = rs[(size_t)0]; BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) == _tstring(_T("1 group")), "group_name = 1 group " << string(rs[(size_t)0][_T("group_name")].a_str())); sortFields orderRv; orderRv.add(_T("group_name"), false); rs.orderBy(orderRv); sortFields order; order.add(_T("group_name"), true); rs.orderBy(order); BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) == _tstring(_T("1 group")), "group_name = 1 group " << string(rs[(size_t)0][_T("group_name")].a_str())); // test union recordset rs2; atu.alias(fd_name, _T("name")); q.reset().select(_T("id"), _T("name"), _T("group")).where(_T("id"), _T("<="), 16000); atu.index(0).keyValue(15001).read(rs2, q); ate.index(0).join(rs2, q.reset().select(_T("comment")).optimize( queryBase::joinHasOneOrHasMany), _T("id")); atg.alias(_T("name"), _T("group_name")); atg.index(0).join(rs2, q.reset().select(_T("group_name")), _T("group")); BOOST_CHECK_MESSAGE(rs2.size() == 1000, "join2 rs2.size()== 1000"); rs += rs2; BOOST_CHECK_MESSAGE(rs.size() == 16000, "union rs.size()== 16000"); // row = rs[15000]; BOOST_CHECK_MESSAGE(rs[15000][_T("id")].i() == 15001, "id = 15001"); // row = rs.last(); BOOST_CHECK_MESSAGE(rs.last()[_T("id")].i() == 16000, "id = 16000"); // test group by groupQuery gq; gq.keyField(_T("group"), _T("id")); client::count count1(_T("count")); gq.addFunction(&count1); client::count count2(_T("gropu1_count")); count2.when(_T("group"), _T("="), 1); gq.addFunction(&count2); rs.groupBy(gq); BOOST_CHECK_MESSAGE(rs.size() == 16000, "group by rs.size()== 16000"); int v = rs[0][_T("gropu1_count")].i(); BOOST_CHECK_MESSAGE(v == 1, "gropu1_count = " << v); // clone recordset* rsv(rs.clone()); gq.reset(); client::count count3(_T("count")); gq.addFunction(&count3).keyField(_T("group")); //.resultField(_T("count")); rs.groupBy(gq); BOOST_CHECK_MESSAGE(rs.size() == 5, "group by2 rs.size()==" << rsv->size()); // having recordsetQuery rq; rq.when(_T("gropu1_count"), _T("="), 1).or_(_T("gropu1_count"), _T("="), 2); rsv->matchBy(rq); BOOST_CHECK_MESSAGE(rsv->size() == 3200, "matchBy rsv.size() ==" << rsv->size()); rsv->release(); // top recordset rs3; rs.top(rs3, 10); BOOST_CHECK_MESSAGE(rs3.size() == 5, "top 10 rs3.size()== 5"); // query new / delete recordsetQuery* q1 = recordsetQuery::create(); q1->when(_T("gropu1_count"), _T("="), 1) .or_(_T("gropu1_count"), _T("="), 2); q1->release(); query* q2 = query::create(); q2->where(_T("gropu1_count"), _T("="), 1) .or_(_T("gropu1_count"), _T("="), 2); q2->release(); groupQuery* q3 = groupQuery::create(); q3->keyField(_T("group"), _T("id")); q3->release(); } void testPrepareJoin(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); atu.alias(fd_name, _T("name")); activeTable atg(db, _T("groups")); atg.alias(_T("name"), _T("group_name")); activeTable ate(db, _T("extention")); recordset rs; query q; q.select(_T("id"), _T("name"), _T("group")).where(_T("id"), _T("<="), _T("?")); pq_handle pq = atu.prepare(q); atu.index(0).keyValue(1).read(rs, pq, 15000); BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size() 15000 bad = " << rs.size()); BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 3, " rs.fieldDefs()->size() 3 bad = " << rs.fieldDefs()->size()); // Join extention::comment q.reset().select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany); pq = ate.prepare(q); ate.index(0).join(rs, pq, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size() 15000 bad = " << rs.size()); BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 4, " rs.fieldDefs()->size() 4 bad = " << rs.fieldDefs()->size()); // test reverse row& last = rs.reverse().first(); BOOST_CHECK_MESSAGE(last[_T("id")].i() == 15000, "last field id == 15000"); BOOST_CHECK_MESSAGE(_tstring(last[_T("comment")].c_str()) == _tstring(_T("15000 comment")), "last field comment"); // Join group::name q.reset().select(_T("group_name")); pq = atg.prepare(q); atg.index(0).join(rs, pq, _T("group")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000"); row& first = rs.last(); BOOST_CHECK_MESSAGE(first[_T("id")].i() == 1, "first field id == 1"); BOOST_CHECK_MESSAGE(_tstring(first[_T("comment")].c_str()) == _tstring(_T("1 comment")), "first field comment"); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); // row_ptr row = rs[15000 - 9]; row& rec = rs[15000 - 9]; BOOST_CHECK_MESSAGE( _tstring(rec[_T("group_name")].c_str()) == _tstring(_T("4 group")), "group_name = 4 group " << string((rec)[_T("group_name")].a_str())); } void testServerPrepareJoin(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); activeTable atg(db, _T("groups")); activeTable ate(db, _T("extention")); atu.alias(fd_name, _T("name")); atg.alias(_T("name"), _T("group_name")); query q; q.select(_T("id"), _T("name"), _T("group")) .where(_T("id"), _T("<="), _T("?")); pq_handle stmt1 = atu.prepare(q, true); BOOST_CHECK_MESSAGE(stmt1 != NULL, " stmt1"); q.reset().select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany); pq_handle stmt2 = ate.prepare(q, true); BOOST_CHECK_MESSAGE(stmt2 != NULL, " stmt2"); q.reset().select(_T("group_name")); pq_handle stmt3 = atg.prepare(q, true); BOOST_CHECK_MESSAGE(stmt3 != NULL, " stmt3"); recordset rs; atu.index(0).keyValue(1).read(rs, stmt1, 15000); BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size()== 15000 bad " << rs.size()); // Join extention::comment ate.index(0).join(rs, stmt2, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size()== 15000"); // test reverse row& last = rs.reverse().first(); BOOST_CHECK_MESSAGE(last[_T("id")].i() == 15000, "last field id == 15000"); BOOST_CHECK_MESSAGE(_tstring(last[_T("comment")].c_str()) == _tstring(_T("15000 comment")), "last field comment"); // Join group::name atg.index(0).join(rs, stmt3, _T("group")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000"); row& first = rs.last(); BOOST_CHECK_MESSAGE(first[_T("id")].i() == 1, "first field id == 1"); BOOST_CHECK_MESSAGE(_tstring(first[_T("comment")].c_str()) == _tstring(_T("1 comment")), "first field comment"); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); BOOST_CHECK_MESSAGE( _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")), "first field group_name " << string(first[_T("group_name")].a_str())); // row_ptr row = rs[15000 - 9]; row& rec = rs[15000 - 9]; BOOST_CHECK_MESSAGE( _tstring(rec[_T("group_name")].c_str()) == _tstring(_T("4 group")), "group_name = 4 group " << string((rec)[_T("group_name")].a_str())); // Test orderby rs.orderBy(_T("group_name")); // rec = rs[(size_t)0]; BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) == _tstring(_T("1 group")), "group_name = 1 group " << string(rs[(size_t)0][_T("group_name")].a_str())); sortFields orderRv; orderRv.add(_T("group_name"), false); rs.orderBy(orderRv); sortFields order; order.add(_T("group_name"), true); rs.orderBy(order); BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) == _tstring(_T("1 group")), "group_name = 1 group " << string(rs[(size_t)0][_T("group_name")].a_str())); //All fields rs.clear(); q.reset().all(); q.where(_T("id"), _T("<="), _T("?")); stmt1 = atu.prepare(q, true); atu.keyValue(1).read(rs, stmt1, 15000); BOOST_CHECK_MESSAGE(rs.size() == 15000, "read rs.size()== 15000"); if (rs.size() == 15000) { for (int i=0;i<15000;++i) BOOST_CHECK_MESSAGE(rs[i][_T("id")].i() == i+1, "All fields field Value"); } ate.join(rs, stmt2, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size()== 15000"); atg.join(rs, stmt3, _T("group")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000"); // OuterJoin #define NO_RECORD_ID 5 table_ptr tb = ate.table(); tb->setFV(_T("id"), NO_RECORD_ID); tb->seek(); if (tb->stat() == 0) tb->del(); BOOST_CHECK_MESSAGE(tb->stat() == 0, "ate delete id = 5"); q.reset().select(_T("comment"), _T("blob")).optimize(queryBase::joinHasOneOrHasMany); stmt2 = ate.prepare(q, true); // Join is remove record(s) no join target record. rs.clear(); atu.keyValue(1).read(rs, stmt1, 15000); ate.join(rs, stmt2, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 14999, "join rs.size()== 14999"); BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1][_T("comment")].i() == NO_RECORD_ID+1, "row of 5 : '6 comment'"); const _TCHAR* vs = rs[NO_RECORD_ID-1][_T("blob")].c_str(); bool ret = _tcscmp(vs, _T("6 blob")) == 0; BOOST_CHECK_MESSAGE(ret == true, "row of 5 : '6 blob'" ); // OuterJoin is no remove record(s) no join target record. rs.clear(); atu.keyValue(1).read(rs, stmt1, 15000); ate.outerJoin(rs, stmt2, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "outerJoin rs.size()== 15000"); atg.outerJoin(rs, stmt3, _T("group")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000"); BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord"); BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'"); vs = rs[NO_RECORD_ID][_T("blob")].c_str(); ret = _tcscmp(vs, _T("6 blob")) == 0; BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'"); // OuterJoin All Join fields q.reset().optimize(queryBase::joinHasOneOrHasMany).all(); stmt2 = ate.prepare(q, true); rs.clear(); atu.keyValue(1).read(rs, stmt1, 15000); ate.outerJoin(rs, stmt2, _T("id")); BOOST_CHECK_MESSAGE(rs.size() == 15000, "outerJoin rs.size()== 15000"); BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord"); BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'"); vs = rs[NO_RECORD_ID][_T("blob")].c_str(); ret = _tcscmp(vs, _T("6 blob")) == 0; BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'"); field fd = rs[NO_RECORD_ID][_T("binary")]; ret = compBlobField(NO_RECORD_ID + 1, fd); BOOST_CHECK_MESSAGE(ret == true, "row of 6 = 'binary 256 byte'"); // Test clone blob field recordset& rs2 = *rs.clone(); BOOST_CHECK_MESSAGE(rs2.size() == 15000, "outerJoin rs2.size()== 15000"); BOOST_CHECK_MESSAGE(rs2[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord"); BOOST_CHECK_MESSAGE(rs2[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'"); vs = rs2[NO_RECORD_ID][_T("blob")].c_str(); ret = _tcscmp(vs, _T("6 blob")) == 0; BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'"); //hasManyJoin inner rs.clear(); q.reset().reject(0xFFFF).limit(0).all(); atg.keyValue(1).read(rs, q); BOOST_CHECK_MESSAGE(rs.size() == 100, "hasManyJoin rs.size()== 100"); q.all().optimize(queryBase::joinHasOneOrHasMany); atu.index(1).join(rs, q, _T("code")); BOOST_CHECK_MESSAGE(rs.size() == 20000, "hasManyJoin rs.size()== 20000"); //hasManyJoin outer rs.clear(); q.reset().reject(0xFFFF).limit(0).all(); atg.keyValue(1).read(rs, q); BOOST_CHECK_MESSAGE(rs.size() == 100, "hasManyJoin rs.size()== 100"); q.all().optimize(queryBase::joinHasOneOrHasMany); atu.index(1).outerJoin(rs, q, _T("code")); BOOST_CHECK_MESSAGE(rs.size() == 20095, "hasManyJoin rs.size()== 20095"); // restore record unsigned char bin[256]; tb->clearBuffer(); tb->setFV(_T("id"), NO_RECORD_ID); tb->setFV(_T("comment"), _T("5 comment")); tb->setFV(_T("blob"), _T("5 blob")); fillBlobField(3, NO_RECORD_ID, tb.get(), bin); tb->insert(); BOOST_CHECK_MESSAGE(tb->stat() == 0, "ate insert id = 5"); if (tb->stat()) { atu.release(); atg.release(); ate.release(); db->drop(); } } void testReadMore(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); atu.alias(fd_name, _T("name")); query q; q.select(_T("id"), _T("name"), _T("group")) .where(_T("name"), _T("="), _T("1*")) .reject(70).limit(8).stopAtLimit(true); pq_handle stmt1 = atu.prepare(q, true); BOOST_CHECK_MESSAGE(stmt1 != NULL, " stmt1"); recordset rs; atu.index(0).keyValue(18).read(rs, stmt1); BOOST_CHECK_MESSAGE(rs.size() == 2, "read"); recordset rs2; atu.readMore(rs2); BOOST_CHECK_MESSAGE(rs2.size() == 8, "readMore"); rs += rs2; BOOST_CHECK_MESSAGE(rs.size() == 10, "union"); } void testFirstLastGroupFunction(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); atu.alias(fd_name, _T("name")); query q; q.select(_T("id"), _T("name"), _T("group")) .where(_T("name"), _T("="), _T("1*")) .reject(70).limit(8).stopAtLimit(true); pq_handle stmt1 = atu.prepare(q, true); BOOST_CHECK_MESSAGE(stmt1 != NULL, " stmt1"); recordset rs; atu.index(0).keyValue(0).read(rs, stmt1); BOOST_CHECK_MESSAGE(rs.size() == 8, "read"); groupQuery gq; fieldNames target; target.addValue(_T("name")); client::last last(target, _T("last_rec_name")); client::first first(target, _T("first_rec_name")); gq.addFunction(&last); gq.addFunction(&first); rs.groupBy(gq); BOOST_CHECK_MESSAGE(rs.size() == 1, "read"); BOOST_CHECK_MESSAGE(rs[0][_T("first_rec_name")].c_str() == std::_tstring(_T("1 user")), "first_rec_name"); BOOST_CHECK_MESSAGE(rs[0][_T("last_rec_name")].c_str() == std::_tstring(_T("16 user")), "last_rec_name"); } void testBlobOnlyTable(database* db) { // table access test table* tb = db->openTable(_T("blobonly")); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); tb->clearBuffer(); static const int id = 1; tb->setFV((short)0, id); tb->seek(); field fd = tb->fields()[_T("binary")]; bool ret = compBlobField(id, fd); BOOST_CHECK_MESSAGE(ret == true, "tb->seek binary 256 byte"); tb->release(); // activeTable test activeTable at(db, _T("blobonly")); recordset rs; client::query q; q.where(_T("id"), _T("<"), 10); at.index(0).keyValue(1).read(rs, q); BOOST_CHECK_MESSAGE(rs.size() == 9, " rs.size() 9 bad = " << rs.size()); for (int i= 0; i < 9; ++i) { fd = rs[i][_T("binary")]; ret = compBlobField(i+1, fd); BOOST_CHECK_MESSAGE(ret == true, "rs[n][binary] binary 256 byte"); } } void testWirtableRecord(database* db) { #ifdef LINUX const char* fd_name = "名前"; #else #ifdef _UNICODE const wchar_t fd_name[] = { L"名前" }; #else char fd_name[30]; WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL); #endif #endif activeTable atu(db, _T("user")); writableRecord& rec = atu.index(0).getWritableRecord(); rec[_T("id")] = 120000; rec[fd_name] = _T("aiba"); rec.save(); rec.clear(); rec[_T("id")] = 120000; rec.read(); BOOST_CHECK_MESSAGE(_tstring(rec[fd_name].c_str()) == _tstring(_T("aiba")), "rec 120000 name "); rec.clear(); rec[_T("id")] = 120001; bool r = rec.read(); rec[fd_name] = _T("oono"); if (!r) rec.insert(); else rec.update(); rec.clear(); rec[_T("id")] = 120001; rec.read(); BOOST_CHECK_MESSAGE(_tstring(rec[1].c_str()) == _tstring(_T("oono")), "rec 120001 name "); // update changed filed only rec.clear(); rec[_T("id")] = 120001; rec[fd_name] = _T("matsumoto"); rec.update(); rec.clear(); rec[_T("id")] = 120001; rec.read(); BOOST_CHECK_MESSAGE(_tstring(rec[fd_name].c_str()) == _tstring(_T("matsumoto")), "rec 120001 update name "); rec.del(); rec[_T("id")] = 120000; rec.del(); rec.clear(); rec[_T("id")] = 120001; bool ret = rec.read(); BOOST_CHECK_MESSAGE(ret == false, "rec 120001 delete "); rec.clear(); rec[_T("id")] = 120000; ret = rec.read(); BOOST_CHECK_MESSAGE(ret == false, "rec 120000 delete "); } void testDbPool() { pooledDbManager poolMgr; pooledDbManager::setMaxConnections(4); connectParams pm(PROTOCOL, HOSTNAME, _T("querytest"), DBNAME, g_userName, g_password); poolMgr.use(&pm); BOOST_CHECK_MESSAGE(1 == poolMgr.usingCount(), "usingCount 1"); poolMgr.use(&pm); BOOST_CHECK_MESSAGE(2 == poolMgr.usingCount(), "usingCount 2"); poolMgr.use(&pm); BOOST_CHECK_MESSAGE(3 == poolMgr.usingCount(), "usingCount 3"); poolMgr.unUse(); BOOST_CHECK_MESSAGE(0 == poolMgr.usingCount(), "usingCount 0"); //snapshot method { poolMgr.use(&pm); table_ptr tb2 = openTable(poolMgr.db(), _T("user")); poolMgr.use(&pm); table_ptr tb = openTable(poolMgr.db(), _T("user")); poolMgr.beginSnapshot(MULTILOCK_GAP_SHARE); tb->seekFirst(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst"); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst tb2 stat = " << tb2->stat()); poolMgr.endSnapshot(); tb2->seekFirst(ROW_LOCK_X); BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst"); } poolMgr.endSnapshot(); poolMgr.reset(0); } //-------------------------------------------------------------------------------------- // filter test //-------------------------------------------------------------------------------------- #define FILTER_DB _T("filter_test") const _TCHAR* fdf_names[] = { _T("ft_string"), _T("ft_wstring"), _T("ft_zstring"), _T("ft_wzstring"), _T("ft_mychar"), _T("ft_mywchar"), _T("ft_myvarchar"), _T("ft_mywvarchar"), _T("ft_myvarbinary"), _T("ft_mywvarbinary"), }; char fdf_types[] = { ft_string, ft_wstring, ft_zstring, ft_wzstring, ft_mychar, ft_mywchar, ft_myvarchar, ft_mywvarchar, ft_myvarbinary, ft_mywvarbinary, }; #define FILTER_RECORDS 15 const _TCHAR* fd_values[15] = { _T("090-xxxx-xxx"), _T("090-xxxx-xxx"), _T(" "), _T("090-xxxx-xxx"), _T("080-xxxx-xxx"), _T("0"), _T(""), _T(""), _T("09"), _T("070"), _T(""), _T("090-xxxx-xxx"), _T("a90-xxxx-xxx"), _T("Aa0-xxxx-xxx"), _T("A90-xxxx-xxx"), }; void intFieldTypes(database* db) { if (!isUtf16leSupport(db)) { for (int i = 0; i < 10; i++) { if ((i % 2) == 1) fdf_types[i] = fdf_types[i-1]; } } } void inserFilterTestRecords(database* db) { table* tb = db->openTable(_T("user"), TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "openTable stat = " << db->stat()); db->beginTrn(); for (int i = 0; i < FILTER_RECORDS; ++i) { tb->clearBuffer(); tb->setFV((short)0, i); //set AllFields smae value for (int j=0;j<10;++j) tb->setFV(j+1, fd_values[i]); tb->insert(); BOOST_CHECK_MESSAGE(0 == tb->stat(), "insert stat = " << tb->stat()); } db->endTrn(); tb->release(); } void createFilterTestDb(database* db) { db->create(makeUri(PROTOCOL, HOSTNAME, FILTER_DB, BDFNAME)); if (db->stat() == STATUS_TABLE_EXISTS_ERROR) { db->open(makeUri(PROTOCOL, HOSTNAME, FILTER_DB, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "open stat = " << db->stat()); db->drop(); BOOST_CHECK_MESSAGE(0 == db->stat(), "drop stat = " << db->stat()); db->create(makeUri(PROTOCOL, HOSTNAME, FILTER_DB, BDFNAME)); } BOOST_CHECK_MESSAGE(0 == db->stat(), "createFilterTestDb stat = " << db->stat()); // create table db->open(makeUri(PROTOCOL, HOSTNAME, FILTER_DB, BDFNAME), TYPE_SCHEMA_BDF, TD_OPEN_NORMAL); BOOST_CHECK_MESSAGE(0 == db->stat(), "createFilterTestDb 1 stat = " << db->stat()); intFieldTypes(db); dbdef* def = db->dbDef(); if (def) { /* user table */ tabledef td; memset(&td, 0, sizeof(tabledef)); td.setTableName(_T("user")); td.setFileName(_T("user.dat")); td.id = 1; td.primaryKeyNum = -1; td.parentKeyNum = -1; td.replicaKeyNum = -1; td.pageSize = 2048; #ifdef _WIN32 td.charsetIndex = CHARSET_CP932; #else td.charsetIndex = CHARSET_UTF8; #endif def->insertTable(&td); BOOST_CHECK_MESSAGE(0 == def->stat(), "insertTable stat = " << def->stat()); fielddef* fd = def->insertField(1, 0); fd->setName(_T("id")); fd->type = ft_integer; fd->len = (ushort_td)4; for (int i=0;i<10;++i) { fielddef* fd = def->insertField(1, i+1); fd->setName(fdf_names[i]); fd->type = fdf_types[i]; fd->setLenByCharnum(20); } def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 1 stat = " << def->stat()); keydef* kd = def->insertKey(1, 0); kd->segments[0].fieldNum = 0; kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; for (int i=0;i<10;++i) { kd = def->insertKey(1, i+1); kd->segments[0].fieldNum = i+1; kd->segments[0].flags.bit0 = 1; // duplicate kd->segments[0].flags.bit8 = 1; // extended key type kd->segments[0].flags.bit1 = 1; // changeable kd->segmentCount = 1; } def->updateTableDef(1); BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef 3 stat = " << def->stat()); inserFilterTestRecords(db); } } void setReject(query& q) { q.reject(0).limit(0); } void setReject(pq_handle& q) { } template void doTestReadByQuery(int num, activeTable& at, recordset& rs, Q& q, int compSize, const char* msg) { setReject(q); at.index(0).keyValue(0).read(rs, q); BOOST_CHECK_MESSAGE(compSize == (int)rs.size(), num << " " << msg << " rs.size() = " << rs.size()); } void testFilterOfServer(database* db) { intFieldTypes(db); { activeTable atu(db, _T("user")); recordset rs; query q; for (int i = 0; i < 10; ++i) { // empty string q.reset().where(fdf_names[i], _T("="), _T("")); int n = 3; if (atu.table()->tableDef()->fieldDefs[i+1].usePadChar()) n += 1; doTestReadByQuery(i, atu, rs, q, n, ""); q.where(fdf_names[i], _T("=i"), _T("")); doTestReadByQuery(i, atu, rs, q, n, "=i"); // match complate q.where(fdf_names[i], _T("="), _T("070")); doTestReadByQuery(i, atu, rs, q, 1, "= 070"); q.where(fdf_names[i], _T("=i"), _T("070")); doTestReadByQuery(i, atu, rs, q, 1, "=i 070"); // match complate q.where(fdf_names[i], _T("<"), _T("09")); doTestReadByQuery(i, atu, rs, q, 7, "< 09"); q.where(fdf_names[i], _T(" 0) { q.where(fdf_names[i], _T("="), _T("?")); pq_handle pq = atu.prepare(q, (j == 2)); supplyValue(pq, 0, _T("09*")); doTestReadByQuery(i, atu, rs, pq, 5, "prepare = 09*"); q.where(fdf_names[i], _T("=i"), _T("?")); pq_handle pq1 = atu.prepare(q, (j == 2)); supplyValue(pq1, 0, _T("09*")); doTestReadByQuery(i, atu, rs, pq1, 5, "prepare =i 09*"); }else { q.where(fdf_names[i], _T("="), _T("09*")); doTestReadByQuery(i, atu, rs, q, 5, "= 09*"); q.where(fdf_names[i], _T("=i"), _T("09*")); doTestReadByQuery(i, atu, rs, q, 5, "=i 09*"); } } // ascii q.where(fdf_names[i], _T("="), _T("a*")); doTestReadByQuery(i, atu, rs, q, 1, " = a*"); q.where(fdf_names[i], _T("=i"), _T("a*")); doTestReadByQuery(i, atu, rs, q, 3, " =i a*"); q.where(fdf_names[i], _T("="), _T("A*")); doTestReadByQuery(i, atu, rs, q, 2, " = A*"); q.where(fdf_names[i], _T("=i"), _T("A*")); doTestReadByQuery(i, atu, rs, q, 3, " =i A*"); q.where(fdf_names[i], _T("="), _T("AA0*")); doTestReadByQuery(i, atu, rs, q, 0, " = AA0*"); q.where(fdf_names[i], _T("=i"), _T("AA0*")); doTestReadByQuery(i, atu, rs, q, 1, " =i Aa0*"); //case in-sencitive index no jaudge for (int i = 0 ; i < 10 ; ++i) { q.where(fdf_names[i], _T("="), _T("A*")); setReject(q); atu.index(i+1).keyValue(_T("A")).read(rs, q); BOOST_CHECK_MESSAGE(2 == rs.size(), i << " " << "jaudge = A*" << " rs.size() = " << rs.size()); BOOST_CHECK_MESSAGE(atu.table()->statReasonOfFind() == STATUS_REACHED_FILTER_COND, i << " " << "jaudge = A* FILTER_COND"); q.where(fdf_names[i], _T("=i"), _T("A*")); setReject(q); atu.index(i+1).keyValue(_T("A")).read(rs, q); BOOST_CHECK_MESSAGE(3 == rs.size(), i << " " << "jaudge = A*" << " rs.size() = " << rs.size()); BOOST_CHECK_MESSAGE(atu.table()->statReasonOfFind() == STATUS_EOF, i << " " << "jaudge = A* STATUS_EOF"); } } } } void doTestMatchBy(int num, recordset& rs, recordsetQuery& rq, int compSize, const _TCHAR* msg) { recordset* rss = rs.clone(); rss->matchBy(rq); BOOST_CHECK_MESSAGE(compSize == (int)rss->size(), num << msg << _T(" rss->size = ") << rss->size()); rss->release(); } void testFilterOfMatchBy(database* db) { intFieldTypes(db); { activeTable atu(db, _T("user")); query q; recordset rs; atu.index(0).keyValue(0).read(rs, q.all()); BOOST_CHECK_MESSAGE(FILTER_RECORDS == rs.size(), " rs.size() = " << rs.size()); for (int i = 0; i < 10; ++i) { // empty string recordsetQuery rq; rq.when(fdf_names[i], _T("="), _T("")); int n = 3; if (atu.table()->tableDef()->fieldDefs[i+1].usePadChar()) n += 1; doTestMatchBy(i, rs, rq, n, _T(" = ")); rq.reset().when(fdf_names[i], _T("=i"), _T("")); doTestMatchBy(i, rs, rq, n, _T(" =i ")); // wildcard rq.reset().when(fdf_names[i], _T("="), _T("09*")); doTestMatchBy(i, rs, rq, 5, _T(" = 09*")); rq.reset().when(fdf_names[i], _T("=i"), _T("09*")); doTestMatchBy(i, rs, rq, 5, _T(" =i 09*")); // match complate rq.reset().when(fdf_names[i], _T("="), _T("070")); doTestMatchBy(i, rs, rq, 1, _T(" = 070")); rq.reset().when(fdf_names[i], _T("=i"), _T("070")); doTestMatchBy(i, rs, rq, 1, _T(" =i 070")); // match complate rq.reset().when(fdf_names[i], _T("<"), _T("09")); doTestMatchBy(i, rs, rq, 7, _T(" < 09")); rq.reset().when(fdf_names[i], _T("open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME))) db()->drop(); testCreateNewDataBase(db()); } BOOST_FIXTURE_TEST_CASE(clone, fixture) { testClone(db()); } BOOST_FIXTURE_TEST_CASE(version, fixture) { testVersion(db()); } BOOST_FIXTURE_TEST_CASE(insert, fixture) { testInsert(db()); } BOOST_FIXTURE_TEST_CASE(find, fixture) { testFind(db()); } BOOST_FIXTURE_TEST_CASE(findNext, fixture) { testFindNext(db()); testFindIn(db()); testPrepare(db()); testPrepareServer(db()); } BOOST_FIXTURE_TEST_CASE(getPercentage, fixture) { testGetPercentage(db()); } BOOST_FIXTURE_TEST_CASE(movePercentage, fixture) { testMovePercentage(db()); } BOOST_FIXTURE_TEST_CASE(getEqual, fixture) { testGetEqual(db()); } BOOST_FIXTURE_TEST_CASE(getNext, fixture) { testGetNext(db()); } BOOST_FIXTURE_TEST_CASE(getPrevious, fixture) { testGetPrevious(db()); } BOOST_FIXTURE_TEST_CASE(getGreater, fixture) { testGetGreater(db()); } BOOST_FIXTURE_TEST_CASE(getLessThan, fixture) { testGetLessThan(db()); } BOOST_FIXTURE_TEST_CASE(getFirst, fixture) { testGetFirst(db()); } BOOST_FIXTURE_TEST_CASE(getLast, fixture) { testGetLast(db()); } BOOST_FIXTURE_TEST_CASE(movePosition, fixture) { testMovePosition(db()); } BOOST_FIXTURE_TEST_CASE(update, fixture) { testUpdate(db()); } BOOST_FIXTURE_TEST_CASE(snapShot, fixture) { testSnapshot(db()); } BOOST_FIXTURE_TEST_CASE(conflict, fixture) { testConflict(db()); } BOOST_FIXTURE_TEST_CASE(transactionLockRepeatable, fixture) { testTransactionLockRepeatable(db()); } BOOST_FIXTURE_TEST_CASE(bug_015, fixture) { testBug_015(db()); } BOOST_FIXTURE_TEST_CASE(issue_016, fixture) { testIssue_016(db()); } BOOST_FIXTURE_TEST_CASE(transactionLock, fixture) { testTransactionLockReadCommited(db()); } BOOST_FIXTURE_TEST_CASE(RecordLock, fixture) { testRecordLock(db()); } BOOST_FIXTURE_TEST_CASE(MultiDatabase, fixture) { testMultiDatabase(db()); } BOOST_AUTO_TEST_CASE(Exclusive) { testExclusive(); } BOOST_FIXTURE_TEST_CASE(MissingUpdate, fixture) { testMissingUpdate(db()); } BOOST_FIXTURE_TEST_CASE(reconnect, fixture) { testReconnect(db()); } BOOST_FIXTURE_TEST_CASE(insert2, fixture) { testInsert2(db()); } BOOST_FIXTURE_TEST_CASE(delete_, fixture) { testDelete(db()); } BOOST_FIXTURE_TEST_CASE(setOwner, fixture) { testSetOwner(db()); } BOOST_FIXTURE_TEST_CASE(createIndex, fixture) { testCreateIndex(db()); } BOOST_FIXTURE_TEST_CASE(dropIndex, fixture) { testDropIndex(db()); } BOOST_FIXTURE_TEST_CASE(dropDatabase, fixture) { testDropDatabase(db()); } BOOST_FIXTURE_TEST_CASE(grantReload, fixture) { testGrantReload(db()); } BOOST_FIXTURE_TEST_CASE(connect, fixture) { testLogin(db()); } BOOST_AUTO_TEST_SUITE_END() // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ #ifdef LINUX #include BOOST_AUTO_TEST_SUITE(convert) BOOST_AUTO_TEST_CASE(u8tombc) { char mbc[256]; char u8[256] = "123"; bzs::env::u8tombc(u8, -1, mbc, 256); BOOST_CHECK_MESSAGE(!strcmp(mbc, u8), u8); strcpy(u8, "漢字"); unsigned char mbcKanji[20] = { 0x8A, 0xBF, 0x8E, 0x9A, 0x00 }; bzs::env::u8tombc(u8, -1, mbc, 256); BOOST_CHECK_MESSAGE(!strcmp(mbc, (const char*)mbcKanji), u8); memset(u8, 0, 256); bzs::env::mbctou8(mbc, -1, u8, 256); BOOST_CHECK_MESSAGE(!strcmp(u8, "漢字"), "漢字2"); } BOOST_AUTO_TEST_SUITE_END() #endif // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ BOOST_AUTO_TEST_SUITE(var_field) BOOST_FIXTURE_TEST_CASE(createDataBaseVar, fixtureKanji) { testCreateDataBaseVar(db()); } BOOST_FIXTURE_TEST_CASE(varField, fixtureKanji) { testVarField(db()); } BOOST_FIXTURE_TEST_CASE(varInsert, fixtureKanji) { testVarInsert(db()); } BOOST_FIXTURE_TEST_CASE(varRead, fixtureKanji) { testVarRead(db()); } BOOST_FIXTURE_TEST_CASE(filterVar, fixtureKanji) { testFilterVar(db()); } BOOST_FIXTURE_TEST_CASE(dropDataBaseVar, fixtureKanji) { testDropDataBaseVar(db()); } BOOST_AUTO_TEST_SUITE_END() // ------------------------------------------------------------------------ #ifdef TDAP // ------------------------------------------------------------------------ BOOST_AUTO_TEST_SUITE(filter) BOOST_FIXTURE_TEST_CASE(stringFileter, fixtureKanji) { testStringFileter(db()); } BOOST_FIXTURE_TEST_CASE(dropDataBaseStr, fixtureKanji) { testDropDataBaseStr(db()); } BOOST_AUTO_TEST_SUITE_END() // ------------------------------------------------------------------------ #endif // ------------------------------------------------------------------------ BOOST_AUTO_TEST_SUITE(kanjiSchema) BOOST_FIXTURE_TEST_CASE(knajiCreateSchema, fixtureKanji) { testKnajiCreateSchema(db()); } BOOST_FIXTURE_TEST_CASE(insertKanji, fixtureKanji) { testInsertKanji(db()); } BOOST_FIXTURE_TEST_CASE(getEqualKanji, fixtureKanji) { testGetEqualKanji(db()); } BOOST_FIXTURE_TEST_CASE(dropDatabaseKanji, fixtureKanji) { testDropDatabaseKanji(db()); } BOOST_AUTO_TEST_SUITE_END() // ------------------------------------------------------------------------ BOOST_AUTO_TEST_SUITE(filter) BOOST_FIXTURE_TEST_CASE(resultField, fixture) { if (db()->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME))) db()->drop(); testCreateNewDataBase(db()); testResultField(db()); testResultDef(); testLogic(db()); testQuery(); } BOOST_FIXTURE_TEST_CASE(drop, fixture) { testDropDatabase(db()); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(query) BOOST_FIXTURE_TEST_CASE(new_delete, fixtureQuery) { teetNewDelete(db()); } BOOST_FIXTURE_TEST_CASE(join, fixtureQuery) { testJoin(db()); testRecordsetClone(db()); testPrepareJoin(db()); testServerPrepareJoin(db()); testWirtableRecord(db()); } BOOST_FIXTURE_TEST_CASE(readMore, fixtureQuery) { testReadMore(db()); } BOOST_FIXTURE_TEST_CASE(firstLastGropuFunction, fixtureQuery) { testFirstLastGroupFunction(db()); } BOOST_FIXTURE_TEST_CASE(blobOnly, fixtureQuery) { testBlobOnlyTable(db()); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(dbPool) BOOST_AUTO_TEST_CASE(pool) { testDbPool(); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(filter) BOOST_FIXTURE_TEST_CASE(serverFilter, fixture) { createFilterTestDb(db()); testFilterOfServer(db()); testFilterOfMatchBy(db()); } BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(field) BOOST_AUTO_TEST_CASE(binary) { testBinaryField(); } BOOST_AUTO_TEST_CASE(fuga) { BOOST_CHECK_EQUAL(2 * 3, 6); } BOOST_AUTO_TEST_SUITE_END() // ------------------------------------------------------------------------