transactd 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/BUILD_UNIX-JA +6 -6
  3. data/README +16 -16
  4. data/README-JA +16 -16
  5. data/bin/common/tdclc_32_2_1.dll +0 -0
  6. data/bin/common/tdclc_64_2_1.dll +0 -0
  7. data/build/common/transactd_cl_common.cmake +0 -1
  8. data/build/common/transactd_common.cmake +28 -38
  9. data/build/swig/ruby/ruby.swg +36 -30
  10. data/build/swig/ruby/tdclrb_wrap.cpp +35016 -0
  11. data/build/swig/tdcl.i +217 -62
  12. data/build/tdclc/CMakeLists.txt +14 -26
  13. data/build/tdclc/libtdclcm.map +4 -0
  14. data/build/tdclc/tdclc.cbproj +1 -1
  15. data/build/tdclc/tdclc.rc +0 -0
  16. data/build/tdclcpp/CMakeLists.txt +7 -22
  17. data/build/tdclcpp/tdclcpp.rc +0 -0
  18. data/build/tdclcpp/tdclcpp_bc.cbproj +1 -1
  19. data/build/tdclrb/CMakeLists.txt +7 -49
  20. data/build/tdclrb/tdclrb.rc +62 -0
  21. data/source/bzs/db/blobBuffer.h +5 -0
  22. data/source/bzs/db/blobStructs.h +2 -0
  23. data/source/bzs/db/engine/mysql/IReadRecords.h +9 -0
  24. data/source/bzs/db/engine/mysql/database.cpp +391 -169
  25. data/source/bzs/db/engine/mysql/database.h +178 -40
  26. data/source/bzs/db/engine/mysql/dbManager.cpp +45 -3
  27. data/source/bzs/db/engine/mysql/dbManager.h +3 -39
  28. data/source/bzs/db/engine/mysql/errorMessage.cpp +11 -7
  29. data/source/bzs/db/engine/mysql/errorMessage.h +1 -1
  30. data/source/bzs/db/engine/mysql/mydebuglog.cpp +1 -2
  31. data/source/bzs/db/engine/mysql/mysqlInternal.h +8 -8
  32. data/source/bzs/db/engine/mysql/mysqlThd.cpp +11 -0
  33. data/source/bzs/db/protocol/hs/hsCommandExecuter.cpp +1 -1
  34. data/source/bzs/db/protocol/tdap/client/activeTable.cpp +41 -6
  35. data/source/bzs/db/protocol/tdap/client/activeTable.h +177 -8
  36. data/source/bzs/db/protocol/tdap/client/activeTableImple.h +141 -62
  37. data/source/bzs/db/protocol/tdap/client/client.cpp +39 -35
  38. data/source/bzs/db/protocol/tdap/client/client.h +52 -25
  39. data/source/bzs/db/protocol/tdap/client/connectionPool.cpp +17 -0
  40. data/source/bzs/db/protocol/tdap/client/connectionPool.h +1 -0
  41. data/source/bzs/db/protocol/tdap/client/database.cpp +5 -1
  42. data/source/bzs/db/protocol/tdap/client/database.h +1 -1
  43. data/source/bzs/db/protocol/tdap/client/databaseFactory.cpp +49 -12
  44. data/source/bzs/db/protocol/tdap/client/databaseManager.h +42 -5
  45. data/source/bzs/db/protocol/tdap/client/dbDef.cpp +4 -2
  46. data/source/bzs/db/protocol/tdap/client/dllmain.cpp +71 -41
  47. data/source/bzs/db/protocol/tdap/client/errorMessage_ja.cpp +49 -49
  48. data/source/bzs/db/protocol/tdap/client/field.cpp +22 -13
  49. data/source/bzs/db/protocol/tdap/client/field.h +7 -3
  50. data/source/bzs/db/protocol/tdap/client/fieldDDF.cpp +1 -1
  51. data/source/bzs/db/protocol/tdap/client/fieldNameAlias.cpp +0 -1
  52. data/source/bzs/db/protocol/tdap/client/fieldNameAlias.h +1 -0
  53. data/source/bzs/db/protocol/tdap/client/fields.h +111 -24
  54. data/source/bzs/db/protocol/tdap/client/fileDDF.cpp +1 -1
  55. data/source/bzs/db/protocol/tdap/client/filter.h +687 -310
  56. data/source/bzs/db/protocol/tdap/client/groupQuery.cpp +12 -4
  57. data/source/bzs/db/protocol/tdap/client/indexDDF.cpp +1 -1
  58. data/source/bzs/db/protocol/tdap/client/memRecord.cpp +190 -32
  59. data/source/bzs/db/protocol/tdap/client/memRecord.h +64 -22
  60. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +4 -4
  61. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +4 -2
  62. data/source/bzs/db/protocol/tdap/client/nsTable.cpp +6 -3
  63. data/source/bzs/db/protocol/tdap/client/nsTable.h +1 -1
  64. data/source/bzs/db/protocol/tdap/client/pooledDatabaseManager.h +19 -8
  65. data/source/bzs/db/protocol/tdap/client/recordsetImple.h +194 -87
  66. data/source/bzs/db/protocol/tdap/client/request.h +84 -26
  67. data/source/bzs/db/protocol/tdap/client/stringConverter.h +22 -12
  68. data/source/bzs/db/protocol/tdap/client/table.cpp +494 -286
  69. data/source/bzs/db/protocol/tdap/client/table.h +48 -5
  70. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +133 -87
  71. data/source/bzs/db/protocol/tdap/client/trdboostapiInternal.h +22 -22
  72. data/source/bzs/db/protocol/tdap/client/trdormapi.h +43 -18
  73. data/source/bzs/db/protocol/tdap/client/trnsctcl.def +3 -3
  74. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.cpp +1 -0
  75. data/source/bzs/db/protocol/tdap/mysql/recordsetReader.h +268 -74
  76. data/source/bzs/db/protocol/tdap/mysql/request.h +4 -4
  77. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +179 -43
  78. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.h +4 -4
  79. data/source/bzs/db/protocol/tdap/tdapRequest.h +15 -14
  80. data/source/bzs/db/protocol/tdap/tdapSchema.h +125 -90
  81. data/source/bzs/db/protocol/tdap/tdapcapi.h +46 -5
  82. data/source/bzs/db/transactd/appModule.h +1 -1
  83. data/source/bzs/db/transactd/connManager.cpp +2 -0
  84. data/source/bzs/db/transactd/transactd.cpp +1 -0
  85. data/source/bzs/env/compiler.h +10 -0
  86. data/source/bzs/env/mbcswchrLinux.cpp +42 -6
  87. data/source/bzs/env/mbcswchrLinux.h +40 -12
  88. data/source/bzs/example/queryData.cpp +33 -4
  89. data/source/bzs/netsvc/client/iconnection.h +107 -0
  90. data/source/bzs/netsvc/client/tcpClient.cpp +15 -1
  91. data/source/bzs/netsvc/client/tcpClient.h +96 -87
  92. data/source/bzs/netsvc/server/serverCpt.cpp +5 -6
  93. data/source/bzs/rtl/benchmark.cpp +2 -2
  94. data/source/bzs/rtl/stringBuffers.cpp +3 -3
  95. data/source/bzs/rtl/stringBuffers.h +2 -2
  96. data/source/bzs/test/tdclatl/bench_query_atl.js +92 -99
  97. data/source/bzs/test/tdclatl/test_query_atl.js +224 -115
  98. data/source/bzs/test/tdclphp/bench.php +126 -101
  99. data/source/bzs/test/tdclphp/transactd_Test.php +1122 -158
  100. data/source/bzs/test/tdclrb/bench_tdclcpp.rb +12 -14
  101. data/source/bzs/test/tdclrb/transactd_spec.rb +1127 -142
  102. data/source/bzs/test/transactdBench/query_bench.cpp +32 -15
  103. data/source/bzs/test/transactdBench/scaling_bench.cpp +32 -7
  104. data/source/bzs/test/transactdBench/transactdBench.cpp +1 -1
  105. data/source/bzs/test/transactdBench/workerBase.h +46 -0
  106. data/source/bzs/test/transactdBench/workerMySQLImple.h +15 -7
  107. data/source/bzs/test/transactdBench/workerTransactdImple.h +10 -18
  108. data/source/bzs/test/trdclengn/test_trdclengn.cpp +1487 -174
  109. data/source/global/ormsrcgen/main.cpp +2 -0
  110. data/source/global/tdclatl/Database.cpp +2 -2
  111. data/source/global/tdclatl/Database.h +1 -1
  112. data/source/global/tdclatl/FieldDefs.cpp +0 -3
  113. data/source/global/tdclatl/PooledDbManager.cpp +2 -2
  114. data/source/global/tdclatl/PooledDbManager.h +1 -1
  115. data/source/global/tdclatl/PreparedQuery.cpp +53 -0
  116. data/source/global/tdclatl/PreparedQuery.h +61 -0
  117. data/source/global/tdclatl/QueryBase.cpp +2 -1
  118. data/source/global/tdclatl/QueryBase.h +1 -1
  119. data/source/global/tdclatl/Record.cpp +3 -15
  120. data/source/global/tdclatl/Recordset.cpp +15 -10
  121. data/source/global/tdclatl/Recordset.h +3 -0
  122. data/source/global/tdclatl/Table.cpp +42 -7
  123. data/source/global/tdclatl/Table.h +3 -1
  124. data/source/global/tdclatl/activeTable.cpp +264 -76
  125. data/source/global/tdclatl/activeTable.h +12 -3
  126. data/source/global/tdclatl/tdclatl.idl +92 -10
  127. data/source/linux/charsetConvert.h +7 -7
  128. data/transactd.gemspec +14 -27
  129. metadata +18 -27
  130. data/bin/common/tdclc_32_2_0.dll +0 -0
  131. data/bin/common/tdclc_64_2_0.dll +0 -0
  132. data/build/swig/php/generate.cmake.in +0 -56
  133. data/build/swig/php/generate.cmd.in +0 -47
  134. data/build/swig/php/php.swg +0 -197
  135. data/build/swig/php/transactd.no_yield.php +0 -4494
  136. data/build/swig/php/transactd.no_yield.php.git.patch +0 -685
  137. data/build/swig/php/transactd.no_yield.php.patch +0 -685
  138. data/build/swig/php/transactd.yield.php +0 -4461
  139. data/build/swig/php/transactd.yield.php.git.patch +0 -652
  140. data/build/swig/php/transactd.yield.php.patch +0 -652
  141. data/build/swig/ruby/generate.cmake.in +0 -35
  142. data/build/swig/ruby/generate.cmd.in +0 -19
  143. data/build/tdclc/BUILDNUMBER.txt +0 -1
  144. data/build/tdclcpp/BUILDNUMBER.txt +0 -1
  145. data/build/tdclrb/BUILDNUMBER.txt +0 -1
  146. data/build/tdclrb/GEM_RELEASE_VERSION +0 -1
@@ -16,6 +16,13 @@
16
16
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17
17
  02111-1307, USA.
18
18
  =================================================================*/
19
+ #ifdef _MSC_VER
20
+ #ifdef _DEBUG
21
+ #define _CRTDBG_MAP_ALLOC
22
+ #include <stdlib.h>
23
+ #include <crtdbg.h>
24
+ #endif // _DEBUG
25
+ #endif // _MSC_VER
19
26
  #include <bzs/db/protocol/tdap/client/activeTable.h>
20
27
  #include <bzs/rtl/benchmark.h>
21
28
  #include <bzs/example/queryData.h>
@@ -63,33 +70,37 @@ bool btest(recordset* rsp, activeTable* atup, activeTable* atgp,
63
70
  activeTable& ate = *atep;
64
71
  recordset& rs = *rsp;
65
72
  query q;
73
+ q.select(_T("id"), _T("name"), _T("group"))
74
+ .where(_T("id"), _T("<="), _T("?"));
75
+ atu.alias(fd_name, _T("name"));
76
+ pq_handle stmt = atu.prepare(q, true);
77
+ if (!stmt) return false;
78
+
79
+ q.reset().select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany);
80
+ pq_handle stmt2 = ate.prepare(q, true);
81
+ if (!stmt2) return false;
82
+
83
+ atg.alias(_T("name"), _T("group_name"));
84
+ q.reset().select(_T("group_name"));
85
+ pq_handle stmt3 = atg.prepare(q, true);
86
+ if (!stmt3) return false;
66
87
 
67
88
  for (int i = 0; i < n; ++i)
68
89
  {
69
90
  rs.clear();
70
91
  if (kind & 1)
71
92
  {
72
- q.reset();
73
- atu.alias(fd_name, _T("name"));
74
-
75
- q.select(_T("id"), _T("name"), _T("group"))
76
- .where(_T("id"), _T("<="), i + 15000);
77
- atu.index(0).keyValue(i + 1).read(rs, q);
78
-
93
+ supplyValue(stmt, 0, i + 15000);
94
+ atu.index(0).keyValue(i + 1).read(rs, stmt);
79
95
  // Join extention::comment
80
96
  if (kind & 2)
81
97
  {
82
- q.reset();
83
- ate.index(0).join(rs, q.select(_T("comment")).optimize(
84
- queryBase::joinHasOneOrHasMany),
85
- _T("id"));
98
+ ate.index(0).join(rs, stmt2, _T("id"));
86
99
  }
87
100
  if (kind & 4)
88
101
  {
89
102
  // Join group::name
90
- q.reset();
91
- atg.alias(_T("name"), _T("group_name"));
92
- atg.index(0).join(rs, q.select(_T("group_name")), _T("group"));
103
+ atg.index(0).join(rs, stmt3, _T("group"));
93
104
  }
94
105
  }
95
106
  if (kind & 8)
@@ -110,6 +121,7 @@ int _tmain(int argc, _TCHAR* argv[])
110
121
  database_ptr db = createDatabaseObject();
111
122
  try
112
123
  {
124
+ {
113
125
  const _TCHAR* host = _T("localhost");
114
126
  int kind = 15;
115
127
  int n = 100;
@@ -134,6 +146,7 @@ int _tmain(int argc, _TCHAR* argv[])
134
146
  std::tcout << "The query data build error." << std::endl;
135
147
  return 1;
136
148
  }
149
+
137
150
  activeTable atu(db, _T("user"));
138
151
  activeTable atg(db, _T("groups"));
139
152
  activeTable ate(db, _T("extention"));
@@ -143,7 +156,11 @@ int _tmain(int argc, _TCHAR* argv[])
143
156
  bzs::rtl::benchmark bm;
144
157
  bm.report(boost::bind(btest, &rs, &atu, &atg, &ate, kind, n),
145
158
  "exec time ");
146
-
159
+ }
160
+ db.reset();
161
+ #ifdef _MSC_VER
162
+ _CrtDumpMemoryLeaks();
163
+ #endif
147
164
  return 0;
148
165
  }
149
166
 
@@ -27,9 +27,10 @@ typedef std::vector<boost::shared_ptr<workerBase> > workers;
27
27
 
28
28
  struct transactionSec
29
29
  {
30
- transactionSec() : value(0) {}
30
+ transactionSec() : value(0),timeOne(0) {}
31
31
  int workes;
32
32
  __int64 value;
33
+ double timeOne;
33
34
  };
34
35
 
35
36
  struct commandLineParam
@@ -59,13 +60,21 @@ void showResult(const std::vector<transactionSec>& results, int total,
59
60
  int totalTransactionTime, int totalTransactions,
60
61
  bool stressMode)
61
62
  {
63
+
62
64
  std::tcout << _T("----------------------------------") << std::endl;
63
65
  std::tcout << _T("Clients \tTransactions/sec") << std::endl;
64
66
  std::tcout << _T("----------------------------------") << std::endl;
65
67
 
66
68
  for (int i = 0; i < (int)results.size(); ++i)
67
- std::tcout << results[i].workes << _T("\t") << results[i].value
69
+ {
70
+ if (!stressMode)
71
+ std::tcout << results[i].workes << _T("\t") << results[i].value
72
+ << _T("\t") << results[i].timeOne
68
73
  << std::endl;
74
+ else
75
+ std::tcout << results[i].workes << _T("\t") << results[i].value
76
+ << std::endl;
77
+ }
69
78
  if (!stressMode)
70
79
  {
71
80
  std::tcout << _T("----------------------------------") << std::endl;
@@ -90,7 +99,10 @@ bool tableFixer(const connectParams& param)
90
99
  short index = def->tableNumByName(_T("cache"));
91
100
  if (index == -1 && !createCacheTable(def))
92
101
  return false;
102
+ try{
93
103
  dropTable(db, _T("cache"));
104
+ }
105
+ catch(...){}
94
106
  openTable(db, _T("cache"));
95
107
  return true;
96
108
  }
@@ -139,18 +151,22 @@ double executeWorkers(const commandLineParam& cmd, const connectParams param,
139
151
  }
140
152
  printf("*");
141
153
  fflush(stdout);
142
- Sleep(200 * MCRTOMM);
154
+ Sleep(500 * MCRTOMM);
143
155
  sync.wait(); // start all workers
144
156
  if (cmd.stressMode)
145
157
  {
146
158
  Sleep(200 * MCRTOMM);
147
159
  g_bench_signal = BENCH_SIGNAL_GREEN;
160
+ //Measurement interval
148
161
  Sleep((unsigned int)(BENCH_TIMER_SECONDS * 1000 * MCRTOMM));
149
162
  g_bench_signal = BENCH_SIGNAL_BREAK;
150
163
  }
151
164
  threads.join_all();
152
165
  for (int i = 0; i < wn; ++i)
166
+ {
153
167
  t += workers[i]->total();
168
+ //std::tcout << _T("Execute Workers = ") << wn << " " << workers[i]->total() << std::endl;
169
+ }
154
170
  }
155
171
  return t;
156
172
  }
@@ -172,11 +188,15 @@ int execute(const commandLineParam& cmd, const connectParams param,
172
188
  }
173
189
  else
174
190
  {
191
+ int n = wn * cmd.loopCount * cmd.avg_count;
175
192
  totalTransactionTime += t;
176
- totalTransactions += wn * cmd.loopCount * cmd.avg_count;
193
+ totalTransactions += n;
177
194
  if (t)
195
+ {
196
+ ts.timeOne = t / n / 1000000.0f;
178
197
  ts.value = (__int64)((double)1000000.0f * wn * wn *
179
- cmd.avg_count * cmd.loopCount / t);
198
+ cmd.avg_count * cmd.loopCount / t);
199
+ }
180
200
  }
181
201
  ts.workes = wn;
182
202
  results.push_back(ts);
@@ -251,9 +271,11 @@ int _tmain(int argc, _TCHAR* argv[])
251
271
  printf("\n");
252
272
  showResult(results, bm.end(), (int)totalTransactionTime,
253
273
  totalTransactions, cmd.stressMode);
254
- return 0;
274
+ pooledDbManager pdb;
275
+ pdb.reset(0);
276
+ //return 0;
255
277
  }
256
- return 1;
278
+ //return 1;
257
279
  }
258
280
 
259
281
  catch (bzs::rtl::exception& e)
@@ -261,5 +283,8 @@ int _tmain(int argc, _TCHAR* argv[])
261
283
  std::_tstring s = *bzs::rtl::getMsg(e);
262
284
  std::tcout << _T("[ERROR] ") << s << std::endl;
263
285
  }
286
+ #ifdef _MSC_VER
287
+ _CrtDumpMemoryLeaks();
288
+ #endif
264
289
  return 1;
265
290
  }
@@ -262,7 +262,7 @@ bool createTestDataBase(client::database* db, const _TCHAR* uri)
262
262
  db->create(uri);
263
263
  if (db->stat() != 0)
264
264
  {
265
- printf("createTestDataBase erorr:No.%d %s\r\n", db->stat(), uri);
265
+ _tprintf(_T("createTestDataBase erorr:No.%d %s\r\n"), db->stat(), uri);
266
266
  return false;
267
267
  }
268
268
  if (db->open(uri, TYPE_BDF, TD_OPEN_NORMAL, _T(""), _T("")))
@@ -22,7 +22,12 @@
22
22
  #include <boost/thread/mutex.hpp>
23
23
  #include <bzs/rtl/benchmark.h>
24
24
  #include <iostream>
25
+ #include <bzs/env/tstring.h>
26
+ #include <stdio.h>
25
27
 
28
+ #ifdef _WIN32
29
+ #include <windows.h>
30
+ #endif
26
31
  namespace bzs
27
32
  {
28
33
  namespace test
@@ -49,6 +54,21 @@ protected:
49
54
  virtual void doExecute() = 0;
50
55
  virtual void endExecute(){};
51
56
  virtual void initExecute(){};
57
+ std::_tstring dummyWork()
58
+ {
59
+ std::_tstring s;
60
+ __int64 v = 0;
61
+ for (int i=1;i<100;++i)
62
+ {
63
+ v+=rand();
64
+ v = v/i;
65
+ _TCHAR tmp[30];
66
+ _stprintf_s(tmp, 30, _T("random number %d ."), v);
67
+ s += tmp;
68
+ }
69
+ return s;
70
+ }
71
+
52
72
 
53
73
  public:
54
74
  workerBase(int id, int loopCount, int functionNumber, boost::barrier& sync)
@@ -72,12 +92,38 @@ public:
72
92
  else if (g_bench_signal == BENCH_SIGNAL_BLUE)
73
93
  {
74
94
  m_bresult = bm.end();
95
+ dummyWork();
96
+ break;
97
+ }
98
+ }
99
+
100
+ endExecute();
101
+ }
102
+ #ifdef _WIN32
103
+ void execute2(HANDLE hHandle)
104
+ {
105
+ initExecute();
106
+ bzs::rtl::benchmarkMt bm;
107
+ WaitForSingleObject(hHandle, INFINITE);
108
+
109
+ bm.start();
110
+ m_bresult = 0;
111
+ while (g_bench_signal)
112
+ {
113
+ doExecute();
114
+ if (g_bench_signal == BENCH_SIGNAL_GREEN)
115
+ ++m_bresult;
116
+ else if (g_bench_signal == BENCH_SIGNAL_BLUE)
117
+ {
118
+ m_bresult = bm.end();
119
+ dummyWork();
75
120
  break;
76
121
  }
77
122
  }
78
123
 
79
124
  endExecute();
80
125
  }
126
+ #endif
81
127
  int total() const { return m_bresult; }
82
128
  };
83
129
 
@@ -1,4 +1,4 @@
1
- #ifndef BZS_TEST_BENCH_WORKERMYSQLIMPLE_H
1
+ #ifndef BZS_TEST_BENCH_WORKERMYSQLIMPLE_H
2
2
  #define BZS_TEST_BENCH_WORKERMYSQLIMPLE_H
3
3
  /* =================================================================
4
4
  Copyright (C) 20014 BizStation Corp All rights reserved.
@@ -35,7 +35,7 @@ namespace mysql
35
35
  #define MYSQL_READ_ONE 10
36
36
  #define MYSQL_INSERT_ONE 11
37
37
  #define MYSQL_QUERY 12
38
- #define MYSQL_RECORDSET_COUNT 50
38
+ #define MYSQL_RECORDSET_COUNT 30
39
39
 
40
40
  class connectParam
41
41
  {
@@ -183,10 +183,10 @@ class worker : public workerBase
183
183
  MYSQL_STMT* init(const char* query)
184
184
  {
185
185
  #ifdef LINUX
186
- const char* fd_name = "���O";
186
+ const char* fd_name = "名前";
187
187
  #else
188
188
  char fd_name[30];
189
- WideCharToMultiByte(CP_UTF8, 0, L"���O", -1, fd_name, 30, NULL, NULL);
189
+ WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL);
190
190
  #endif
191
191
  char tmp[512];
192
192
  if (m_functionNumber == MYSQL_QUERY)
@@ -202,6 +202,7 @@ class worker : public workerBase
202
202
  printf("error: %s\n", mysql_error(m_mysql));
203
203
  bindParam(stmt);
204
204
  bindOutput(stmt);
205
+
205
206
  return stmt;
206
207
  }
207
208
 
@@ -209,7 +210,7 @@ class worker : public workerBase
209
210
  {
210
211
  m_bindParam = m_id % 20000 + 1;
211
212
  mysql_stmt_execute(stmt);
212
- int ret;
213
+ int ret=0;
213
214
  ret = mysql_stmt_fetch(stmt);
214
215
  if (ret)
215
216
  printf("error: %s\n", mysql_error(m_mysql));
@@ -251,8 +252,8 @@ public:
251
252
  : workerBase(id, loopCount, functionNumber, sync), m_parmas(param)
252
253
  {
253
254
  boost::mutex::scoped_lock lck(m_mutex);
254
- mysql_thread_init();
255
-
255
+
256
+
256
257
  m_mysql = mysql_init(NULL);
257
258
  int v = 1;
258
259
  if (NULL == mysql_real_connect(
@@ -261,14 +262,21 @@ public:
261
262
  m_parmas.database.c_str(), m_parmas.port, NULL, 0))
262
263
  printf("error: %s\n", mysql_error(m_mysql));
263
264
  }
265
+
264
266
 
265
267
  void initExecute()
266
268
  {
269
+ mysql_thread_init();
270
+ mysql_set_character_set(m_mysql, "utf8");
271
+
267
272
  #ifdef USE_SHARED_PREPAREDSTATEMENT
268
273
  if (m_functionNumber == MYSQL_READ_ONE)
269
274
  m_stmt = init(readOneQuery);
270
275
  else if (m_functionNumber == MYSQL_QUERY)
276
+ {
271
277
  m_stmt = init(queryOneQuery);
278
+ queryOne(m_stmt);
279
+ }
272
280
  #endif
273
281
  }
274
282
 
@@ -40,7 +40,7 @@ namespace transactd
40
40
  #define TRD_READ_ONE 0
41
41
  #define TRD_INSERT_ONE 1
42
42
  #define TRD_QUERY 2
43
- #define TRD_RECORDSET_COUNT 50
43
+ #define TRD_RECORDSET_COUNT 30
44
44
 
45
45
  class worker : public workerBase
46
46
  {
@@ -59,7 +59,8 @@ class worker : public workerBase
59
59
  recordset m_rs;
60
60
  void readOne(table_ptr& tb)
61
61
  {
62
- int v = (rand() % 15000) + 1;
62
+ //int v = (rand() % 15000) + 1;
63
+ int v = m_id % 20000 + 1;
63
64
  tb->setFV((short)0, v);
64
65
  tb->seek();
65
66
  if (tb->stat() != 0)
@@ -68,7 +69,8 @@ class worker : public workerBase
68
69
 
69
70
  void insertOne(table_ptr& tb)
70
71
  {
71
- tb->clearBuffer();
72
+ //tb->clearBuffer();
73
+ tb->setFV((short)0, (int)0);
72
74
  tb->setFV(1, m_id);
73
75
  insertRecord(tb);
74
76
  }
@@ -77,25 +79,14 @@ class worker : public workerBase
77
79
  {
78
80
  m_rs.clear();
79
81
  query q;
80
- int v = (rand() % 15000) + 1;
82
+ //int v = (rand() % 15000) + 1;
83
+ int v = m_id % 20000 + 1;
81
84
  q.select(_T("id"), _T("name"), _T("group"))
82
85
  .where(_T("id"), _T("<"), v + TRD_RECORDSET_COUNT);
83
86
  m_atu->index(0).keyValue(v).read(m_rs, q);
84
- q.reset();
85
-
86
- // m_ate->index(0).join(m_rs,
87
- // q.select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany),
88
- // _T("id"));
89
87
 
90
- // Join group::name
91
- /*recordset rs2;
92
-
93
- q.select(_T("group_name"));
94
- for (int i=0;i<m_rs.size();++i)
95
- q.addSeekKeyValuePtr(m_rs[i][(short)0].ptr());
96
- m_atg->table()->setQuery(&q);
97
- m_atg->index(0).keyValue(0).read(rs2, q);
98
- */
88
+ q.reset();
89
+
99
90
  m_atg->index(0).join(m_rs, q.select(_T("group_name")), _T("group"));
100
91
  if (m_rs.size() != TRD_RECORDSET_COUNT)
101
92
  printf("query read error! id = %d size = %d\n", m_id, m_rs.size());
@@ -143,6 +134,7 @@ public:
143
134
  _TCHAR tmp[30];
144
135
  m_atu->alias(name_field_str(tmp), _T("name"));
145
136
  m_atg->alias(_T("name"), _T("group_name"));
137
+ queryOne();
146
138
  }
147
139
  }
148
140
 
@@ -18,6 +18,7 @@
18
18
  ================================================================= */
19
19
  //#define BOOST_TEST_MODULE
20
20
 
21
+
21
22
  #include <boost/test/included/unit_test.hpp>
22
23
  #include <bzs/db/protocol/tdap/client/database.h>
23
24
  #include <bzs/db/protocol/tdap/client/table.h>
@@ -29,14 +30,19 @@
29
30
  #include <bzs/db/protocol/tdap/client/filter.h>
30
31
  #include <bzs/example/queryData.h>
31
32
  #include <bzs/db/protocol/tdap/client/activeTable.h>
32
-
33
33
  #include <bzs/db/protocol/tdap/client/pooledDatabaseManager.h>
34
+ #include <boost/thread.hpp>
34
35
 
35
36
  using namespace bzs::db::protocol::tdap::client;
36
37
  using namespace bzs::db::protocol::tdap;
37
38
  using namespace std;
38
39
 
40
+ #define TDAP
41
+ #ifdef TDAP
39
42
  #define PROTOCOL _T("tdap")
43
+ #else
44
+ #define PROTOCOL _T("btrv")
45
+ #endif
40
46
  static _TCHAR HOSTNAME[MAX_PATH] = { _T("127.0.0.1") };
41
47
  #define DBNAME _T("test")
42
48
  #define BDFNAME _T("test.bdf")
@@ -62,6 +68,9 @@ boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[])
62
68
  #endif
63
69
  }
64
70
  }
71
+ printf("Transactd test ... \nMay look like progress is stopped, \n"
72
+ "but it is such as record lock test, please wait.\n");
73
+
65
74
  return 0;
66
75
  }
67
76
 
@@ -194,6 +203,7 @@ void testCreateNewDataBase(database* db)
194
203
  dbdef* def = db->dbDef();
195
204
  if (def)
196
205
  {
206
+ /* user table */
197
207
  tabledef td;
198
208
  memset(&td, 0, sizeof(tabledef));
199
209
  td.setTableName(_T("user"));
@@ -248,6 +258,48 @@ void testCreateNewDataBase(database* db)
248
258
  def->updateTableDef(1);
249
259
  BOOST_CHECK_MESSAGE(0 == def->stat(),
250
260
  "updateTableDef 3 stat = " << def->stat());
261
+
262
+ /* group table */
263
+ memset(&td, 0, sizeof(tabledef));
264
+ td.setTableName(_T("group"));
265
+ td.setFileName(_T("group"));
266
+ td.id = 2;
267
+ td.primaryKeyNum = -1;
268
+ td.parentKeyNum = -1;
269
+ td.replicaKeyNum = -1;
270
+ td.pageSize = 2048;
271
+ def->insertTable(&td);
272
+ BOOST_CHECK_MESSAGE(0 == def->stat(),
273
+ "insertTable stat = " << def->stat());
274
+
275
+ fd = def->insertField(2, 0);
276
+ fd->setName(_T("id"));
277
+ fd->type = ft_integer;
278
+ fd->len = (ushort_td)4;
279
+ def->updateTableDef(2);
280
+ BOOST_CHECK_MESSAGE(0 == def->stat(),
281
+ "updateTableDef 1 stat = " << def->stat());
282
+
283
+ fd = def->insertField(2, 1);
284
+ fd->setName(_T("name"));
285
+ fd->type = ft_zstring;
286
+ fd->len = (ushort_td)33;
287
+ def->updateTableDef(2);
288
+ BOOST_CHECK_MESSAGE(0 == def->stat(),
289
+ "updateTableDef 2 stat = " << def->stat());
290
+
291
+ kd = def->insertKey(2, 0);
292
+ kd->segments[0].fieldNum = 0;
293
+ kd->segments[0].flags.bit8 = 1; // extended key type
294
+ kd->segments[0].flags.bit1 = 1; // changeable
295
+ kd->segmentCount = 1;
296
+
297
+ def->updateTableDef(2);
298
+ BOOST_CHECK_MESSAGE(0 == def->stat(),
299
+ "updateTableDef 3 stat = " << def->stat());
300
+
301
+
302
+
251
303
  }
252
304
  }
253
305
 
@@ -330,6 +382,20 @@ void testInsert(database* db)
330
382
  tb->release();
331
383
  }
332
384
 
385
+ void findNextLoop(table* tb, int start, int end)
386
+ {
387
+ while (start < end)
388
+ {
389
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat = " << tb->stat());
390
+ if (tb->stat()) break;
391
+
392
+ BOOST_CHECK_MESSAGE(start == tb->getFVint(fdi_id), "find value " << start << " bad = " << tb->getFVint(fdi_id));
393
+ tb->findNext(true);
394
+ ++start;
395
+ }
396
+ BOOST_CHECK_MESSAGE(0 != tb->stat(), "findNext end stat = " << tb->stat());
397
+ }
398
+
333
399
  void testFind(database* db)
334
400
  {
335
401
 
@@ -340,24 +406,18 @@ void testFind(database* db)
340
406
  int v = 10;
341
407
  tb->setFV((short)0, v);
342
408
  tb->find(table::findForword);
343
- int i = v;
344
- while (i < 20000)
345
- {
346
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat");
347
- BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "find value " << i);
348
- tb->findNext(true); // 11 ~ 19
349
- ++i;
350
- }
351
-
409
+ findNextLoop(tb, v, 20000);
410
+
352
411
  // backforword
353
412
  tb->clearBuffer();
354
413
  v = 19999;
355
414
  tb->setFV((short)0, v);
356
415
  tb->find(table::findBackForword);
357
- i = v;
416
+ int i = v;
358
417
  while (i >= 10)
359
418
  {
360
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat");
419
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "find stat = " << tb->stat());
420
+ if (tb->stat()) break;
361
421
  BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "find value " << i);
362
422
  tb->findPrev(true); // 11 ~ 19
363
423
  --i;
@@ -384,7 +444,8 @@ void testFindNext(database* db)
384
444
  for (int i = v + 1; i < 20000; i++)
385
445
  {
386
446
  tb->findNext(true); // 11 ~ 19
387
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "findNext stat()");
447
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "findNext stat()" << tb->stat());
448
+ if (tb->stat()) break;
388
449
  BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "findNext value");
389
450
  }
390
451
  tb->release();
@@ -435,26 +496,25 @@ void testFindIn(database* db)
435
496
 
436
497
  // Many params
437
498
  _TCHAR buf[20];
438
- _ltot_s(1, buf, 20, 10);
439
- q.addSeekKeyValue(buf, true);
440
-
441
- for (int i = 2; i <= 10000; ++i)
499
+ for (int j = 1; j <= 10000; ++j)
442
500
  {
443
- _ltot_s(i, buf, 20, 10);
444
- q.addSeekKeyValue(buf);
501
+ _ltot_s(j, buf, 20, 10);
502
+ q.addSeekKeyValue(buf, (j == 1)/* reset */);
445
503
  }
446
504
  tb->setQuery(&q);
447
505
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "find in stat = " << tb->stat());
448
-
449
- tb->find();
450
506
  int i = 0;
507
+ tb->find();
508
+
451
509
  while (0 == tb->stat())
452
510
  {
453
-
454
- BOOST_CHECK_MESSAGE(++i == tb->getFVint(fdi_id), "findNext in value");
511
+ ++i;
512
+ BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "findNext in value " << i << " = " << tb->getFVint(fdi_id));
513
+ if (i==9999)
514
+ i = 9999;
455
515
  tb->findNext(true);
456
516
  }
457
- BOOST_CHECK_MESSAGE(i == 10000, "findNext in count");
517
+ BOOST_CHECK_MESSAGE(i == 10000, "findNext in count 10000 != " << i);
458
518
  BOOST_CHECK_MESSAGE(9 == tb->stat(), "find in end stat = " << tb->stat());
459
519
 
460
520
  // LogicalCountLimit
@@ -475,6 +535,142 @@ void testFindIn(database* db)
475
535
  tb->release();
476
536
  }
477
537
 
538
+ void testPrepare(database* db)
539
+ {
540
+ table* tb = openTable(db);
541
+ queryBase q;
542
+ q.queryString(_T("id >= ? and id < ?"));
543
+ q.reject(1).limit(0);
544
+ pq_handle stmt = tb->prepare(&q);
545
+ const _TCHAR* vs[2];
546
+ int nn = makeSupplyValues(vs, 2, _T("10"), _T("20000"));
547
+
548
+ //Test too short supply values
549
+ bool ret = supplyValues(stmt, vs, nn -1); //stmt->supplyValues(vs, nn); Bad
550
+ BOOST_CHECK_MESSAGE(ret == false, "supplyValues short");
551
+
552
+ //Test supply values
553
+ ret = supplyValues(stmt, vs, nn);
554
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues true");
555
+
556
+ int v = 10;
557
+ tb->setFV((short)0, v);
558
+ tb->find(table::findForword);
559
+ findNextLoop(tb, v, 20000);
560
+
561
+ supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("10000"))); //stmt->supplyValues(vs, nn); Bad
562
+ tb->setPrepare(stmt);
563
+ v = 100;
564
+ tb->setFV((short)0, v);
565
+ tb->find(table::findForword);
566
+ findNextLoop(tb, v, 10000);
567
+
568
+ const _TCHAR* values[11];
569
+ int n = makeSupplyValues(values, 11, _T("abc"), _T("efg"), _T("efg")
570
+ , _T("abc"), _T("efg"), _T("efg")
571
+ , _T("abc"), _T("efg"), _T("efg")
572
+ , _T("abc"), _T("efg"));
573
+
574
+ BOOST_CHECK_MESSAGE(n == 11, "makeSupplyValues");
575
+
576
+ tb->release();
577
+ }
578
+
579
+ void testPrepareServer(database* db)
580
+ {
581
+ table* tb = openTable(db);
582
+ queryBase q;
583
+ q.queryString(_T("id >= ? and id < ?"));
584
+ q.reject(0xFFFF).limit(0);
585
+ pq_handle stmt = tb->prepare(&q, true);
586
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "prepare stat");
587
+ if (tb->stat()) return ;
588
+
589
+ const _TCHAR* vs[2];
590
+
591
+ bool ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("10"), _T("200"))); //stmt->supplyValues(vs, nn); Bad
592
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues true");
593
+
594
+ tb->setPrepare(stmt);
595
+ BOOST_CHECK_MESSAGE(tb->stat() == 0, "setQuery stmt");
596
+
597
+ int v = 10;
598
+ tb->setFV((short)0, v);
599
+
600
+ // Test Bad direction
601
+ tb->find(table::findBackForword);
602
+ BOOST_CHECK_MESSAGE(1 == tb->stat(), "find direction not equal prepare");
603
+
604
+ tb->find(table::findForword);
605
+ findNextLoop(tb, v, 200);
606
+
607
+ ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("3000")));
608
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues true");
609
+
610
+ tb->setPrepare(stmt);
611
+ BOOST_CHECK_MESSAGE(tb->stat() == 0, "setQuery stmt");
612
+
613
+ v = 100;
614
+ tb->setFV((short)0, v);
615
+ tb->find(table::findForword);
616
+ findNextLoop(tb, v, 3000);
617
+
618
+ // No seek with
619
+ ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("50"), _T("100")));
620
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues ");
621
+ tb->setPrepare(stmt);
622
+ v = 50;
623
+ tb->setFV((short)0, v);
624
+ tb->seek();
625
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seek");
626
+ tb->findNext(false);
627
+ findNextLoop(tb, v, 100);
628
+
629
+ // RecordCount
630
+ ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("50"), _T("100")));
631
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues ");
632
+ tb->setPrepare(stmt);
633
+ uint_td num = tb->recordCount(false);
634
+ BOOST_CHECK_MESSAGE(num == 50, "recordCount ");
635
+
636
+ // Multi prepare statement
637
+ q.reset();
638
+ q.queryString(_T("id < ?"));
639
+ q.reject(0xFFFF).limit(0);
640
+ pq_handle stmt2 = tb->prepare(&q, true);
641
+ ret = supplyValues(stmt2, vs, makeSupplyValues(vs, 1, _T("50")));
642
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues ");
643
+ tb->setPrepare(stmt2);
644
+ v = 1;
645
+ tb->setFV((short)0, v);
646
+ tb->find();
647
+ findNextLoop(tb, v, 50);
648
+
649
+ ret = supplyValues(stmt, vs, makeSupplyValues(vs, 2, _T("100"), _T("3000")));
650
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues ");
651
+ tb->setPrepare(stmt);
652
+ v = 100;
653
+ tb->setFV((short)0, v);
654
+ tb->find(table::findForword);
655
+ findNextLoop(tb, v, 3000);
656
+
657
+ // Seeks prepare statement
658
+ /*q.reset();
659
+ q.queryString(_T("select id"));
660
+ pq_handle stmt3 = tb->prepare(&q, true);
661
+ const _TCHAR* vsi[6];
662
+ makeSupplyValues(vsi, 6, _T("10"), _T("11"), _T("12"), _T("13"),
663
+ _T("14"), _T("15"));
664
+ int keySegments = 1;
665
+ ret = supplyInValues(stmt3, vsi, 6, keySegments);
666
+ BOOST_CHECK_MESSAGE(ret == true, "supplyValues ");
667
+ tb->setPrepare(stmt3);
668
+ tb->find();
669
+ findNextLoop(tb, 10, 16);
670
+ */
671
+ tb->release();
672
+ }
673
+
478
674
  void testGetPercentage(database* db)
479
675
  {
480
676
  table* tb = openTable(db);
@@ -530,7 +726,12 @@ void testGetNext(database* db)
530
726
  BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetNext");
531
727
 
532
728
  for (int i = 3; i < 20002; i++)
729
+ {
533
730
  tb->seekNext();
731
+ BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetNext id: " << i << " bad = " << tb->getFVint(fdi_id));
732
+ if (i != tb->getFVint(fdi_id))
733
+ break;
734
+ }
534
735
  db->endSnapshot();
535
736
  }
536
737
  tb->release();
@@ -539,6 +740,8 @@ void testGetNext(database* db)
539
740
  void testGetPrevious(database* db)
540
741
  {
541
742
  table* tb = openTable(db);
743
+
744
+ // in-snapshot
542
745
  db->beginSnapshot();
543
746
  int vv = 20001;
544
747
  tb->clearBuffer();
@@ -548,13 +751,33 @@ void testGetPrevious(database* db)
548
751
  for (int i = 20000; i > 1; i--)
549
752
  {
550
753
  tb->seekPrev();
551
- BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetPrevious I");
754
+ BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetPrevious id: " << i << " bad = " << tb->getFVint(fdi_id));
755
+ if (i != tb->getFVint(fdi_id))
756
+ break;
757
+
552
758
  }
553
759
  tb->seekPrev();
554
760
  BOOST_CHECK_MESSAGE(_tstring(_T("kosaka")) == _tstring(tb->getFVstr(1)),
555
761
  "GetPrevious kosaka");
556
-
557
762
  db->endSnapshot();
763
+
764
+ //without snapshot
765
+ vv = 20001;
766
+ tb->clearBuffer();
767
+ tb->setFV((short)0, vv);
768
+ tb->seek();
769
+ BOOST_CHECK_MESSAGE(vv == tb->getFVint(fdi_id), "GetPrevious");
770
+ for (int i = 20000; i > 1; i--)
771
+ {
772
+ tb->seekPrev();
773
+ BOOST_CHECK_MESSAGE(i == tb->getFVint(fdi_id), "GetPrevious id: " << i << " bad = " << tb->getFVint(fdi_id));
774
+ if (i != tb->getFVint(fdi_id))
775
+ break;
776
+ }
777
+ tb->seekPrev();
778
+ BOOST_CHECK_MESSAGE(_tstring(_T("kosaka")) == _tstring(tb->getFVstr(1)),
779
+ "GetPrevious kosaka");
780
+
558
781
  tb->release();
559
782
  }
560
783
 
@@ -717,62 +940,140 @@ void testUpdate(database* db)
717
940
  tb->release();
718
941
  }
719
942
 
720
- void testSnapShot(database* db)
943
+ void testSnapshot(database* db)
721
944
  {
945
+ table* tb = openTable(db);
946
+ table* tbg = db->openTable(_T("group"), TD_OPEN_NORMAL);
722
947
  database* db2 = database::create();
723
- db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
724
948
  BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
725
- table* tb = openTable(db);
949
+ db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
726
950
  table* tb2 = openTable(db2);
951
+ table* tbg2 = db2->openTable(_T("group"), TD_OPEN_NORMAL);
727
952
 
728
- db->beginSnapshot();
953
+ /* No locking repeatable read */
954
+ /* -------------------------------------------------- */
955
+ db->beginSnapshot(); // CONSISTENT_READ is default
729
956
  BOOST_CHECK_MESSAGE(0 == db->stat(), "beginSnapShot");
957
+ db->beginTrn();
958
+ BOOST_CHECK_MESSAGE(STATUS_ALREADY_INSNAPSHOT == db->stat(), "Invalid beginSnapshot");
959
+
960
+
730
961
  tb->setKeyNum(0);
731
- tb->seekFirst();
962
+ tb->seekFirst();
732
963
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst");
733
- int firstValue = tb->getFVint(fdi_name);
964
+ _tstring firstValue = tb->getFVstr(fdi_name);
734
965
  tb->seekNext();
735
- /* -------------------------------------------------- */
736
- // Change data by another connection
966
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekNext");
967
+ BOOST_CHECK_MESSAGE(2 == tb->getFVint(fdi_id), "seekNext");
968
+ tbg->seekFirst();
969
+ BOOST_CHECK_MESSAGE(STATUS_EOF == tbg->stat(), "seekFirst tbg");
970
+ BOOST_CHECK_MESSAGE(0 == tbg->recordCount(false), "seekFirst tbg");
971
+
972
+ // Change data by another connection. change 2 tables.
737
973
  tb2->setKeyNum(0);
738
974
  tb2->seekFirst();
739
975
  BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
740
976
  tb2->setFV(fdi_name, tb2->getFVint(fdi_name) + 1);
741
- tb2->update();
742
- #ifdef ISOLATION_READ_COMMITTED
743
- BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update stat = " << tb2->stat());
744
- #else
745
- #ifdef ISOLATION_REPEATABLE_READ
746
- BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(),
977
+ tb2->update(); //Change success
978
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(),
747
979
  "tb2->update stat = " << tb2->stat());
748
- #endif
749
- #endif
750
- /* -------------------------------------------------- */
980
+ tbg2->setFV(fdi_id, 1);
981
+ tbg2->setFV(fdi_name, _T("ABC"));
982
+ tbg2->insert();
983
+ BOOST_CHECK_MESSAGE(0 == tbg2->stat(), "tbg2->insert");
751
984
 
985
+ // in-snapshot repeatable read check same value
752
986
  tb->seekFirst();
753
- int secondValue = tb->getFVint(fdi_name);
987
+ _tstring secondValue = tb->getFVstr(fdi_name);
754
988
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "secondValue");
755
- db->endSnapshot();
989
+ BOOST_CHECK_MESSAGE(secondValue == firstValue, "repeatableRead");
990
+
991
+ tbg->seekFirst();
992
+ BOOST_CHECK_MESSAGE(STATUS_EOF == tbg->stat(), "seekFirst tbg");
993
+ BOOST_CHECK_MESSAGE(0 == tbg->recordCount(false), "seekFirst tbg");
756
994
 
995
+ // test update in snapshot
996
+ tb->update();
997
+ BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb->stat(), "snapshot update stat = " << tb->stat());
998
+
999
+ // test insert in snapshot
1000
+ tb->setFV(fdi_id, 0);
1001
+ tb->insert();
1002
+ BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb->stat(), "snapshot insert stat = " << tb->stat());
1003
+
1004
+ //test phantom read
1005
+ tb2->setFV(fdi_id, 29999);
1006
+ tb2->insert();
1007
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "phantom insert");
1008
+ tb->setFV(fdi_id, 29999);
1009
+ tb->seek();
1010
+ BOOST_CHECK_MESSAGE(STATUS_NOT_FOUND_TI == tb->stat(), "phantom read");
1011
+
1012
+ // clean up
1013
+ tb2->del();
1014
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "del");
1015
+
1016
+ db->endSnapshot();
757
1017
  BOOST_CHECK_MESSAGE(0 == db->stat(), "endSnapShot");
758
- #ifdef ISOLATION_READ_COMMITTED
759
- BOOST_CHECK_MESSAGE(secondValue != firstValue, "repeatableRead");
760
- #else
761
- BOOST_CHECK_MESSAGE(secondValue == firstValue, "repeatableRead");
762
- #endif
1018
+
1019
+ // After snapshot, db can read new versions.
1020
+ tb->seekFirst();
1021
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1022
+ BOOST_CHECK_MESSAGE(1 == tb->getFVint(fdi_name), "read new value = 1");
1023
+ tbg->seekFirst();
1024
+ BOOST_CHECK_MESSAGE(0 == tbg->stat(), "seekFirst tbg");
1025
+ BOOST_CHECK_MESSAGE(1 == tbg->recordCount(false), "seekFirst tbg");
763
1026
 
764
- /* -------------------------------------------------- */
1027
+
1028
+ //test gap lock
1029
+ db->beginSnapshot(MULTILOCK_GAP_SHARE);
1030
+ tb->seekLast(); // id = 30000
1031
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekLast");
1032
+ tb->seekPrev(); // id = 20002
1033
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev");
1034
+ tb->seekPrev(); // id = 20001
1035
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev");
1036
+
1037
+ tb2->setFV(fdi_id, 29999);
1038
+ tb2->insert();
1039
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert");
1040
+
1041
+ db->endSnapshot();
1042
+
1043
+ //test gap lock
1044
+ db->beginSnapshot(MULTILOCK_NOGAP_SHARE);
1045
+ tb->seekLast(); // id = 30000
1046
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekLast");
1047
+ tb->seekPrev(); // id = 20002
1048
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev");
1049
+ tb->seekPrev(); // id = 20001
1050
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekPrev");
1051
+
1052
+ tb2->setFV(fdi_id, 20002);
1053
+ tb2->seek(ROW_LOCK_X);
1054
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert");
1055
+
1056
+
1057
+ tb2->seekLast(ROW_LOCK_X);
1058
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "GAP insert");
1059
+
1060
+
1061
+ db->endSnapshot();
1062
+
1063
+ tbg->release();
1064
+ tbg2->release();
765
1065
  tb->release();
766
1066
  tb2->release();
1067
+
767
1068
  database::destroy(db2);
768
1069
  }
769
1070
 
770
1071
  void testConflict(database* db)
771
1072
  {
1073
+ table* tb = openTable(db);
772
1074
  database* db2 = database::create();
773
1075
  db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
774
1076
  BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
775
- table* tb = openTable(db);
776
1077
  table* tb2 = openTable(db2);
777
1078
 
778
1079
  tb->setKeyNum(0);
@@ -795,9 +1096,9 @@ void testConflict(database* db)
795
1096
  BOOST_CHECK_MESSAGE(STATUS_CHANGE_CONFLICT == tb->stat(), "tb->update(");
796
1097
  /* -------------------------------------------------- */
797
1098
 
798
- /* --------------------------------------------------
799
- Change Non index field
800
- -------------------------------------------------- */
1099
+ /* -------------------------------------------------- */
1100
+ /* Change Non index field */
1101
+ /* -------------------------------------------------- */
801
1102
  // Change data by another connection
802
1103
  tb->seekFirst();
803
1104
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
@@ -817,188 +1118,851 @@ void testConflict(database* db)
817
1118
  database::destroy(db2);
818
1119
  }
819
1120
 
820
- void testTransactionLock(database* db)
1121
+ /* isoration Level ISO_REPEATABLE_READ */
1122
+ void testTransactionLockRepeatable(database* db)
821
1123
  {
822
-
1124
+ table* tb = openTable(db);
823
1125
  database* db2 = database::create();
824
1126
  db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
825
1127
  BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
826
- table* tb = openTable(db);
827
1128
  table* tb2 = openTable(db2);
828
1129
 
829
- // ------------------------------------------------------
830
- // Read test that single record lock with read
831
- // ------------------------------------------------------
832
- db->beginTrn(LOCK_SINGLE_NOWAIT);
833
- tb->setKeyNum(0);
1130
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1131
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1132
+ // Test Invalid operation
1133
+ db->beginSnapshot();
1134
+ BOOST_CHECK_MESSAGE(STATUS_ALREADY_INTRANSACTION == db->stat(), "Invalid beginSnapshot");
1135
+
1136
+ /* -------------------------------------------------*/
1137
+ /* Test Read with lock */
1138
+ /* -------------------------------------------------*/
1139
+ // lock(X) the first record
834
1140
  tb->seekFirst();
835
1141
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
836
1142
 
837
- // unlock first record.
1143
+ // Add lock(X) the second record
838
1144
  tb->seekNext();
839
1145
 
1146
+ // No transaction user can read allways. Use consistent_read
840
1147
  tb2->seekFirst();
841
1148
  BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
842
1149
 
1150
+ tb2->seekNext();
1151
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1152
+
1153
+ // The second transaction user can not lock same record.
843
1154
  db2->beginTrn();
844
1155
  tb2->setKeyNum(0);
1156
+
1157
+ // Try lock(X)
845
1158
  tb2->seekFirst();
846
- BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1159
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
847
1160
  db2->endTrn();
848
1161
  db->endTrn();
849
1162
 
850
- // ------------------------------------------------------
851
- // Can't read test that multi record lock with read
852
- // ------------------------------------------------------
853
- db->beginTrn(LOCK_MULTI_NOWAIT);
854
- tb->setKeyNum(0);
1163
+ /* -------------------------------------------------*/
1164
+ /* Test single record lock and Transaction lock */
1165
+ /* -------------------------------------------------*/
1166
+ // lock(X) non-transaction
1167
+ tb2->seekFirst(ROW_LOCK_X);
1168
+
1169
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1170
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1171
+
1172
+ // Try lock(X)
1173
+ tb->seekFirst();
1174
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst");
1175
+
1176
+ // Remove lock(X)
1177
+ tb2->seekFirst();
1178
+
1179
+ // Retry lock(X)
855
1180
  tb->seekFirst();
856
1181
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
857
1182
 
858
- // move from first record.
859
- tb->seekNext();
1183
+ tb->setFV(fdi_name, _T("ABC"));
1184
+ tb->update();
1185
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
860
1186
 
861
- // The no transaction user can not read .
1187
+ // No transaction user read can read allways. Use consistent_read
862
1188
  tb2->seekFirst();
863
- BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
1189
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1190
+ BOOST_CHECK_MESSAGE(_tstring(_T("ABC")) != _tstring(tb2->getFVstr(fdi_name)), "consistent_read");
864
1191
 
865
- // The second transaction user can not lock same record.
1192
+ /* -------------------------------------------------*/
1193
+ /* Test Transaction lock and Transaction lock */
1194
+ /* -------------------------------------------------*/
866
1195
  db2->beginTrn();
867
- tb2->setKeyNum(0);
1196
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn");
1197
+
1198
+ // try lock(X)
1199
+ tb2->seekFirst();
1200
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
1201
+
1202
+ // Try unlock updated record. Con not unlock updated record.
1203
+ tb->unlock();
1204
+
1205
+ // try lock(X)
868
1206
  tb2->seekFirst();
869
1207
  BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
1208
+
870
1209
  db2->endTrn();
871
1210
  db->endTrn();
872
1211
 
873
- // ------------------------------------------------------
874
- // Can't read test that single record lock with change
875
- // ------------------------------------------------------
876
- db->beginTrn(LOCK_SINGLE_NOWAIT);
877
- tb->setKeyNum(0);
1212
+ /* -------------------------------------------------*/
1213
+ /* Test phantom read */
1214
+ /* -------------------------------------------------*/
1215
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1216
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1217
+
1218
+ // read last row
1219
+ tb->seekLast(); //lock(X) last id = 30000
1220
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast");
1221
+ tb->seekPrev(); //Add lock(X)
1222
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1223
+ int last2 = tb->getFVint(fdi_id);
1224
+
1225
+ // insert test row
1226
+ tb2->setFV(fdi_id, 29999);
1227
+ tb2->insert(); //Can not insert by gap lock
1228
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->insert");
1229
+
1230
+ tb->seekLast();
1231
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast");
1232
+ tb->seekPrev();
1233
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1234
+ BOOST_CHECK_MESSAGE(last2 == tb->getFVint(fdi_id), "phantom read");
1235
+ db->endTrn();
1236
+
1237
+ /* -------------------------------------------------*/
1238
+ /* Test use shared lock option */
1239
+ /* -------------------------------------------------*/
1240
+
1241
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1242
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn1");
1243
+
1244
+ db2->beginTrn(MULTILOCK_REPEATABLE_READ);
1245
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn2");
1246
+
1247
+ tb->seekLast(ROW_LOCK_S);
1248
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast");
1249
+ tb2->seekLast(ROW_LOCK_S);
1250
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekLast");
1251
+
1252
+ tb->seekPrev();//Lock(X)
1253
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1254
+
1255
+ tb2->seekPrev(ROW_LOCK_S);
1256
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekPrev");
1257
+
1258
+ tb->seekPrev(ROW_LOCK_S);
1259
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1260
+ int id = tb->getFVint(fdi_id);
1261
+
1262
+ tb2->setFV(fdi_id, id);
1263
+ tb2->seek(ROW_LOCK_S);
1264
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek");
1265
+
1266
+ db2->endTrn();
1267
+ db->endTrn();
1268
+
1269
+ /* -------------------------------------------------*/
1270
+ /* Test Abort */
1271
+ /* -------------------------------------------------*/
1272
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1273
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1274
+
1275
+ // lock(X)
878
1276
  tb->seekFirst();
879
1277
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
880
- tb->setFV(fdi_name, _T("ABC"));
1278
+ tb->setFV(fdi_name, _T("EFG"));
881
1279
  tb->update();
882
1280
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
883
1281
 
884
1282
  // move from first record.
885
1283
  tb->seekNext();
1284
+ db->abortTrn();
886
1285
 
1286
+ tb2->setKeyNum(0);
887
1287
  tb2->seekFirst();
888
- BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
1288
+ BOOST_CHECK_MESSAGE(_tcscmp(tb2->getFVstr(fdi_name), _T("ABC")) == 0,
1289
+ "tb->seekFirst");
1290
+
1291
+
1292
+ /* -------------------------------------------------*/
1293
+ /* Test Query and locks Multi record lock */
1294
+ /* -------------------------------------------------*/
1295
+ db->beginTrn(MULTILOCK_REPEATABLE_READ);
1296
+
1297
+ // Test find records are lock.
1298
+ query q;
1299
+ q.where(_T("id"), _T("<="), 15).and_(_T("id"), _T("<>"), 13)
1300
+ .reject(0xFFFF);
1301
+ tb->setQuery(&q);
1302
+ tb->setFV(fdi_id, 12);
1303
+ tb->find();
1304
+ while (tb->stat() == 0)
1305
+ tb->findNext();
1306
+ BOOST_CHECK_MESSAGE(15 == tb->getFVint(fdi_id), "find last id");
1307
+
1308
+ //all records locked
1309
+ for (int i = 12 ; i <= 16; ++i)
1310
+ {
1311
+ tb2->setFV(fdi_id, i);
1312
+ tb2->seek(ROW_LOCK_X);
1313
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seek");
1314
+ }
1315
+ db->endTrn();
1316
+
1317
+
1318
+ tb->release();
1319
+ tb2->release();
1320
+ database::destroy(db2);
1321
+ }
1322
+
1323
+ /* isoration Level ISO_READ_COMMITED */
1324
+ void testTransactionLockReadCommited(database* db)
1325
+ {
1326
+ table* tb = openTable(db);
1327
+ database* db2 = database::create();
1328
+ db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
1329
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
1330
+ table* tb2 = openTable(db2);
1331
+
1332
+ /* -------------------------------------------------*/
1333
+ /* Test single record lock Transaction and read */
1334
+ /* -------------------------------------------------*/
1335
+ db->beginTrn(SINGLELOCK_READ_COMMITED);
1336
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1337
+ db->beginSnapshot();
1338
+ BOOST_CHECK_MESSAGE(STATUS_ALREADY_INTRANSACTION == db->stat(), "Invalid beginSnapshot");
1339
+
1340
+ tb->setKeyNum(0);
1341
+ tb->seekFirst(); // lock(X)
1342
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
889
1343
 
1344
+ // Try lock(X)
1345
+ tb2->seekFirst(ROW_LOCK_X);
1346
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst");
1347
+
1348
+ // consistent read
1349
+ tb2->seekFirst();
1350
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1351
+
1352
+ // Unlock first record. And lock(X) second record
1353
+ tb->seekNext();
1354
+
1355
+ // test unlocked first record
1356
+ tb2->seekFirst();
1357
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1358
+ tb2->update();
1359
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->update");
1360
+
1361
+ // The second record, consistent read
1362
+ tb2->seekNext();
1363
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext");
1364
+ // Try lock(X) whith lock(IX)
1365
+ tb2->update();
1366
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->update");
1367
+
1368
+ /* ---------------------------------------------------------*/
1369
+ /* Test single record lock Transaction and Transaction lock */
1370
+ /* ---------------------------------------------------------*/
890
1371
  db2->beginTrn();
891
- tb2->setKeyNum(0);
1372
+ // Try lock(X)
1373
+ tb2->seekFirst();
1374
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1375
+ // Try lock(X)
1376
+ tb2->seekNext();
1377
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekNext");
1378
+ db2->endTrn();
1379
+ db->endTrn();
1380
+
1381
+ /* ------------------------------------------------------------*/
1382
+ /* Test multi record lock Transaction and non-transaction read */
1383
+ /* ------------------------------------------------------------*/
1384
+ db->beginTrn(MULTILOCK_READ_COMMITED);
1385
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1386
+
1387
+ // lock(X) the first record
1388
+ tb->seekFirst();
1389
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1390
+
1391
+ // Add lock(X) the second record
1392
+ tb->seekNext();
1393
+
1394
+ // No transaction user read can read allways. Use consistent_read
1395
+ tb2->seekFirst();
1396
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1397
+
1398
+ tb2->seekNext();
1399
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext");
1400
+
1401
+ /* --------------------------------------*/
1402
+ /* Test unlock */
1403
+ /* --------------------------------------*/
1404
+ tb2->seekFirst();
1405
+ tb2->seekNext(ROW_LOCK_X);
1406
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekNext");
1407
+
1408
+ tb->unlock();
1409
+ // retry seekNext. Before operation is failed but do not lost currency.
1410
+ tb2->seekNext(ROW_LOCK_X);
1411
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "unlock");
1412
+ tb2->seekNext();
1413
+ /* --------------------------------------*/
1414
+ /* Test undate record unlock */
1415
+ /* --------------------------------------*/
1416
+ tb->seekFirst();
1417
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1418
+ tb->seekNext();
1419
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1420
+ tb->update();
1421
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1422
+ tb->unlock();// Can not unlock updated record
1423
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->unlock");
1424
+ tb2->seekFirst();
1425
+ tb2->seekNext(ROW_LOCK_X);
1426
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "undate unlock");
1427
+
1428
+ /* ---------------------------------------------------------*/
1429
+ /* Test multi record lock Transaction and Transaction */
1430
+ /* ---------------------------------------------------------*/
1431
+ db2->beginTrn();
1432
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "beginTrn");
1433
+
1434
+ // Try lock(X)
892
1435
  tb2->seekFirst();
893
1436
  BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb->seekFirst");
894
1437
  db2->endTrn();
895
1438
  db->endTrn();
896
1439
 
897
- // ------------------------------------------------------
898
- // Abort test that Single record lock transaction
899
- // ------------------------------------------------------
900
- db->beginTrn(LOCK_SINGLE_NOWAIT);
901
- tb->setKeyNum(0);
1440
+ /* -------------------------------------------------------------------*/
1441
+ /* Test multi record lock Transaction and non-transaction record lock */
1442
+ /* -------------------------------------------------------------------*/
1443
+ // lock(X) non-transaction
1444
+ tb2->seekFirst(ROW_LOCK_X);
1445
+
1446
+ db->beginTrn(SINGLELOCK_READ_COMMITED);
1447
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1448
+
1449
+ // Try lock(X)
1450
+ tb->seekFirst();
1451
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst");
1452
+
1453
+ // Remove lock(X)
1454
+ tb2->seekFirst();
1455
+
1456
+ // Retry lock(X)
902
1457
  tb->seekFirst();
903
1458
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
904
- tb->setFV(fdi_name, _T("EFG"));
1459
+
1460
+ // update in transaction
1461
+ tb->setFV(fdi_name, _T("ABC"));
905
1462
  tb->update();
906
1463
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
907
1464
 
908
1465
  // move from first record.
909
1466
  tb->seekNext();
910
- db->abortTrn();
911
1467
 
1468
+ // No transaction read can read allways. Use consistent_read
1469
+ tb2->seekFirst();
1470
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1471
+ tb2->update();
1472
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->update");
1473
+
1474
+ db->endTrn();
1475
+ /* -------------------------------------------------*/
1476
+ /* Test phantom read */
1477
+ /* -------------------------------------------------*/
1478
+ db->beginTrn(MULTILOCK_READ_COMMITED);
1479
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1480
+
1481
+ //read last row
1482
+ tb->seekLast(); //lock(X) last id = 30000
1483
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast");
1484
+ tb->seekPrev(); //Add lock(X)
1485
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1486
+ int last2 = tb->getFVint(fdi_id);
1487
+
1488
+ //insert test row
1489
+ tb2->setFV(fdi_id, 29999);
1490
+ tb2->insert();
1491
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->insert");
1492
+
1493
+ tb->seekLast();
1494
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLast");
1495
+ tb->seekPrev();
1496
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekPrev");
1497
+ BOOST_CHECK_MESSAGE(last2 != tb->getFVint(fdi_id), "phantom read");
1498
+ db->endTrn();
1499
+
1500
+ //cleanup
1501
+ tb2->del(); // last id = 29999
1502
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->del");
1503
+
1504
+ /* -------------------------------------------------*/
1505
+ /* TAbort test */
1506
+ /* -------------------------------------------------*/
1507
+ db->beginTrn(SINGLELOCK_READ_COMMITED);
1508
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "beginTrn");
1509
+
1510
+ tb->seekFirst();
1511
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1512
+ tb->setFV(fdi_name, _T("EFG"));
1513
+ tb->update();
1514
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
1515
+
1516
+ tb->seekNext();
1517
+ db->abortTrn();
912
1518
  tb2->setKeyNum(0);
913
1519
  tb2->seekFirst();
914
1520
  BOOST_CHECK_MESSAGE(_tcscmp(tb2->getFVstr(fdi_name), _T("ABC")) == 0,
915
1521
  "tb->seekFirst");
916
1522
 
1523
+ /* -------------------------------------------------*/
1524
+ /* Test Query and locks Single record lock */
1525
+ /* -------------------------------------------------*/
1526
+ db->beginTrn(SINGLELOCK_READ_COMMITED);
1527
+
1528
+ // Test find last record locked
1529
+ query q;
1530
+ q.where(_T("id"), _T("<="), _T("100"));
1531
+ tb->setQuery(&q);
1532
+ tb->setFV(fdi_id, 1);
1533
+ tb->find();
1534
+ while (tb->stat() == 0)
1535
+ tb->findNext();
1536
+ BOOST_CHECK_MESSAGE(100 == tb->getFVint(fdi_id), "find last id");
1537
+
1538
+ // find read last is record of id = 101.
1539
+ // Would be difficult to identify the last
1540
+ // access to records at SINGLELOCK_READ_COMMITED.
1541
+ // No match records are unlocked.
1542
+ tb2->setFV(fdi_id, 100);
1543
+ tb2->seek(ROW_LOCK_X);
1544
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek");
1545
+ tb2->setFV(fdi_id, 101);
1546
+ tb2->seek(ROW_LOCK_X);
1547
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek");
1548
+ tb2->unlock();
1549
+ db->endTrn();
1550
+
1551
+ /* -------------------------------------------------*/
1552
+ /* Test Query and locks Multi record lock */
1553
+ /* -------------------------------------------------*/
1554
+ db->beginTrn(MULTILOCK_READ_COMMITED);
1555
+
1556
+ // Test find records are lock.
1557
+ q.reset().where(_T("id"), _T("<="), 15).and_(_T("id"), _T("<>"), 13)
1558
+ .reject(0xFFFF);
1559
+ tb->setQuery(&q);
1560
+ tb->setFV(fdi_id, 12);
1561
+ tb->find();
1562
+ while (tb->stat() == 0)
1563
+ tb->findNext();
1564
+ BOOST_CHECK_MESSAGE(15 == tb->getFVint(fdi_id), "find last id");
1565
+
1566
+
1567
+ for (int i = 12 ; i <= 16; ++i)
1568
+ {
1569
+ tb2->setFV(fdi_id, i);
1570
+ tb2->seek(ROW_LOCK_X);
1571
+ if ((i == 16)|| (i == 13))
1572
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seek");
1573
+ else
1574
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seek");
1575
+ }
1576
+ db->endTrn();
917
1577
  tb->release();
918
1578
  tb2->release();
919
1579
  database::destroy(db2);
920
1580
  }
921
1581
 
922
- void testExclusive()
1582
+ void testRecordLock(database* db)
923
1583
  {
1584
+ table* tb = openTable(db);
1585
+ database* db2 = database::create();
1586
+ db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
1587
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
1588
+ table* tb2 = openTable(db2);
924
1589
 
1590
+ tb->setKeyNum(0);
1591
+ tb2->setKeyNum(0);
1592
+
1593
+ //Single record lock
1594
+ tb->seekFirst(ROW_LOCK_X); // lock(X)
1595
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1596
+ tb2->seekFirst(); // Use consistent_read
1597
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1598
+
1599
+ tb2->seekFirst(ROW_LOCK_X); // Try lock(X) single
1600
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst");
1601
+
1602
+ // try consistent_read. Check ended that before auto transaction
1603
+ tb2->seekFirst();
1604
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1605
+
1606
+ tb2->seekNext(ROW_LOCK_X); // lock(X) second
1607
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1608
+
1609
+ tb2->seekNext(ROW_LOCK_X); // lock(X) third second lock freed
1610
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1611
+
1612
+
1613
+ tb->seekNext(); // nobody lock second.
1614
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1615
+ tb->seekNext(ROW_LOCK_X); // Try lock(X) third
1616
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst");
1617
+
1618
+ //Update test change third with lock(X)
1619
+ tb2->setFV(fdi_name, _T("The 3rd"));
1620
+ tb2->update(); // auto trn commit and unlock all locks
1621
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update");
1622
+ tb2->seekNext(ROW_LOCK_X); // lock(X) 4th
1623
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1624
+ tb2->setFV(fdi_name, _T("The 4th"));
1625
+ tb2->update(); // auto trn commit and unlock all locks
1626
+
1627
+ // Test unlock all locks, after update
1628
+ tb->seekFirst(ROW_LOCK_X); // lock(X) first
1629
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekFirst");
1630
+ tb->seekNext(ROW_LOCK_X); // lock(X) second
1631
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext");
1632
+ tb->seekNext(ROW_LOCK_X); // lock(X) third
1633
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb->seekNext");
1634
+ BOOST_CHECK_MESSAGE(_tcscmp(tb->getFVstr(fdi_name), _T("The 3rd")) == 0,
1635
+ "tb->seekNext");
1636
+ //Test Insert, After record lock operation
1637
+ tb->setFV(fdi_id, 21000);
1638
+ tb->insert();
1639
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->insert");
1640
+ tb->del();
1641
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->del");
1642
+
1643
+ /* --------- Unlock test ----------------------------*/
1644
+ // 1 unlock()
1645
+ tb->seekFirst(ROW_LOCK_X);
1646
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1647
+
1648
+ tb->unlock();
1649
+
1650
+ tb2->seekFirst(ROW_LOCK_X);
1651
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1652
+ tb2->unlock();
1653
+
1654
+ //2 auto tran ended
1655
+ table* tb3 = openTable(db2);
1656
+ tb2->seekFirst(ROW_LOCK_X);
1657
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1658
+
1659
+ tb3->seekLast(); //This operation is another table handle, then auto tran ended
1660
+ BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekLast");
1661
+
1662
+ tb->seekFirst(ROW_LOCK_X);
1663
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1664
+ tb->unlock();
1665
+
1666
+ // begin trn
1667
+ tb3->seekFirst(ROW_LOCK_X);
1668
+ BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekFirst");
1669
+
1670
+ tb->seekFirst(ROW_LOCK_X);
1671
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst");
1672
+ db2->beginTrn();
1673
+
1674
+ tb->seekFirst(ROW_LOCK_X);
1675
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1676
+ db2->endTrn();
1677
+ tb->unlock();
1678
+ // begin snapshot
1679
+ tb3->seekFirst(ROW_LOCK_X);
1680
+ BOOST_CHECK_MESSAGE(0 == tb3->stat(), "tb3->seekFirst");
1681
+
1682
+ tb->seekFirst(ROW_LOCK_X);
1683
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb->stat(), "tb->seekFirst");
1684
+ db2->beginSnapshot();
1685
+ tb->seekFirst(ROW_LOCK_X);
1686
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1687
+ db2->endSnapshot();
1688
+ tb->unlock();
1689
+ // close Table
1690
+ tb->seekFirst(ROW_LOCK_X);
1691
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1692
+
1693
+ tb2->seekFirst(ROW_LOCK_X);
1694
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(), "tb2->seekFirst");
1695
+ tb->release();
1696
+ tb2->seekFirst(ROW_LOCK_X);
1697
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1698
+ tb2->unlock();
1699
+ /* --------- End Unlock test ----------------------------*/
1700
+
1701
+ /* --------- Invalid lock type test ----------------------------*/
1702
+ tb2->seekFirst(ROW_LOCK_S);
1703
+ BOOST_CHECK_MESSAGE(STATUS_INVALID_LOCKTYPE == tb2->stat(), "tb2->seekFirst");
1704
+
1705
+ tb2->release();
1706
+ tb3->release();
1707
+ database::destroy(db2);
1708
+
1709
+ }
1710
+
1711
+ void testExclusive()
1712
+ {
925
1713
  // db mode exclusive
926
1714
  database* db = database::create();
1715
+ /* -------------------------------------------------*/
1716
+ /* database WRITE EXCLUSIVE */
1717
+ /* -------------------------------------------------*/
927
1718
  table* tb = openTable(db, TD_OPEN_EXCLUSIVE);
928
1719
  BOOST_CHECK_MESSAGE(0 == db->stat(), "Exclusive opened 1 ");
929
1720
 
930
1721
  // Can not open another connections.
931
1722
  database* db2 = database::create();
932
- db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
933
- BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
934
- db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
935
- BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat(),
936
- "open 1" << db->stat());
1723
+ db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
1724
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
1725
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
1726
+ //database open error. Check database::stat()
1727
+ BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat(),
1728
+ "open db->stat = " << db->stat());
1729
+ dbdef* def = db->dbDef();
1730
+ tabledef* td = def->tableDefs(1);
1731
+ td->iconIndex = 3;
1732
+ def->updateTableDef(1);
1733
+ BOOST_CHECK_MESSAGE(0 == def->stat(), "updateTableDef");
1734
+ tb->release();
1735
+ db->close();
1736
+ db2->close();
1737
+
1738
+ /* -------------------------------------------------*/
1739
+ /* database READ EXCLUSIVE */
1740
+ /* -------------------------------------------------*/
1741
+ tb = openTable(db, TD_OPEN_READONLY_EXCLUSIVE);
1742
+
1743
+ // Read only open
1744
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
1745
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "read only open");
1746
+ db2->close();
1747
+
1748
+ // Normal open
1749
+ db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
1750
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME),
1751
+ TYPE_SCHEMA_BDF, TD_OPEN_NORMAL);
1752
+ BOOST_CHECK_MESSAGE(0 == db2->stat()
1753
+ , "Normal open");
1754
+ db2->close();
1755
+
1756
+ // Write Exclusive open
1757
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME),
1758
+ TYPE_SCHEMA_BDF, TD_OPEN_EXCLUSIVE);
1759
+ BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat()
1760
+ , "Write Exclusive open");
1761
+ db2->close();
1762
+
1763
+ // Read Exclusive open
1764
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME),
1765
+ TYPE_SCHEMA_BDF, TD_OPEN_READONLY_EXCLUSIVE);
1766
+ BOOST_CHECK_MESSAGE(0 == db2->stat()
1767
+ , "Read Exclusive open");
1768
+ db2->close();
1769
+ tb->release();
1770
+ db->close();
1771
+
1772
+ /* -------------------------------------------------*/
1773
+ /* Nnomal and Exclusive opend tables mix use */
1774
+ /* -------------------------------------------------*/
1775
+ tb = openTable(db, TD_OPEN_NORMAL);
1776
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
1777
+
1778
+ table* tb2 = db->openTable(_T("group"), TD_OPEN_EXCLUSIVE);
1779
+ //Check tb2 Exclusive
1780
+ table* tb3 = db2->openTable(_T("group"), TD_OPEN_NORMAL);
1781
+ BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat()
1782
+ , "Write Exclusive open");
1783
+ //if (tb2->recordCount(false) == 0)
1784
+ {
1785
+ for (int i = 1 ; i < 5 ; ++i)
1786
+ {
1787
+ tb2->setFV(fdi_id, i + 1);
1788
+ tb2->setFV(fdi_name, i + 1);
1789
+ tb2->insert();
1790
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->insert");
1791
+ }
1792
+ }
1793
+ tb2->seekFirst();
1794
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1795
+ tb->seekFirst();
1796
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1797
+ tb2->seekLast();
1798
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast");
1799
+ tb->seekLast();
1800
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast");
1801
+ // Normal close first
1802
+ tb->close();
1803
+ tb2->seekLast();
1804
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast");
1805
+ tb2->seekFirst();
1806
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1807
+
1808
+ //Reopen Normal
1809
+ tb = db->openTable(_T("user"));
1810
+ tb2->seekFirst();
1811
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1812
+ tb->seekFirst();
1813
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1814
+ tb2->seekLast();
1815
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLast");
1816
+ tb->seekLast();
1817
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast");
1818
+ // Exclusive close first
1819
+ tb2->close();
1820
+ tb->seekFirst();
1821
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1822
+ tb->seekLast();
1823
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb2->seekLast");
1824
+
1825
+ /* ---------------------------------------------------*/
1826
+ /* Nnomal and Exclusive opend tables mix transaction */
1827
+ /* ---------------------------------------------------*/
1828
+ tb2 = db->openTable(_T("group"), TD_OPEN_EXCLUSIVE);
1829
+ //Check tb2 Exclusive
1830
+ tb3 = db2->openTable(_T("group"), TD_OPEN_NORMAL);
1831
+ BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat()
1832
+ , "Write Exclusive open");
1833
+ db->beginTrn();
1834
+ tb->seekFirst();
1835
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
1836
+ tb->setFV(fdi_name, _T("mix trn"));
1837
+ tb->update();
1838
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->update");
1839
+
1840
+ tb2->seekFirst();
1841
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
1842
+ tb2->setFV(fdi_name, _T("first mix trn tb2"));
1843
+ tb2->update();
1844
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update");
1845
+
1846
+ tb2->seekNext();
1847
+ tb2->setFV(fdi_name, _T("second mix trn tb2"));
1848
+ tb2->update();
1849
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->update");
1850
+ db->endTrn();
1851
+ tb2->seekFirst();
1852
+ _tstring v = tb2->getFVstr(fdi_name);
1853
+ BOOST_CHECK_MESSAGE(v == _T("first mix trn tb2"), "check first");
1854
+ tb2->seekNext();
1855
+ v = tb2->getFVstr(fdi_name);
1856
+ BOOST_CHECK_MESSAGE(v == _T("second mix trn tb2"), "check second");
1857
+
1858
+ database::destroy(db);
1859
+ database::destroy(db2);
1860
+ }
1861
+
1862
+
1863
+ /* Multi database */
1864
+ void testMultiDatabase(database* db)
1865
+ {
1866
+ table* tb = openTable(db);
1867
+ database* db2 = database::create();
1868
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF); // not new connection
1869
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "db2->open");
1870
+ table* tb2 = db2->openTable(_T("group"));
937
1871
 
938
- table* tb2 = db->openTable(_T("user"));
939
- BOOST_CHECK_MESSAGE(0 == db->stat(), "Exclusive opened 2");
1872
+ db->beginTrn();
1873
+ db2->beginTrn();
940
1874
 
941
- tb->setKeyNum(0);
942
1875
  tb->seekFirst();
943
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
944
-
945
- tb->setFV(fdi_name, _T("ABC123"));
1876
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst");
1877
+ _tstring v = tb->getFVstr(fdi_name);
1878
+ tb->setFV(fdi_name, _T("MultiDatabase"));
946
1879
  tb->update();
947
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
948
1880
 
949
- tb2->setKeyNum(0);
950
1881
  tb2->seekFirst();
951
- BOOST_CHECK_MESSAGE(0 == tb2->stat(), "update");
952
- tb2->setFV(fdi_name, _T("ABC124"));
1882
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "seekFirst");
1883
+ tb2->setFV(fdi_name, _T("MultiDatabase"));
953
1884
  tb2->update();
954
1885
  BOOST_CHECK_MESSAGE(0 == tb2->stat(), "update");
1886
+ db2->endTrn();
1887
+ db->abortTrn();
955
1888
 
956
- tb->close();
957
- tb2->close();
958
- db->close();
959
- db2->close();
1889
+ tb->seekFirst();
1890
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "seekFirst");
1891
+ _tstring v2 = tb->getFVstr(fdi_name);
1892
+ BOOST_CHECK_MESSAGE(v == v2, "check value");
1893
+
1894
+ tb->release();
1895
+ tb2->release();
1896
+ database::destroy(db2);
1897
+ }
1898
+
1899
+ class worker
1900
+ {
1901
+ table* m_tb;
1902
+ public:
1903
+ worker(table* tb):m_tb(tb){}
1904
+ void run(){m_tb->seekLessThan(false, ROW_LOCK_X);}
1905
+ };
1906
+ /* Getting missing value by lock wait */
1907
+ void testMissingUpdate(database* db)
1908
+ {
960
1909
 
961
- // table mode exclusive
962
- db = database::create();
963
- tb = openTable(db, TD_OPEN_READONLY, TD_OPEN_EXCLUSIVE);
964
1910
 
965
- db2 = database::create();
1911
+
1912
+ table* tb = openTable(db);
1913
+ database* db2 = database::create();
966
1914
  db2->connect(makeUri(PROTOCOL, HOSTNAME, DBNAME), true);
967
1915
  BOOST_CHECK_MESSAGE(0 == db2->stat(), "connect");
968
- db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
969
- BOOST_CHECK_MESSAGE(0 == db2->stat(), "open 1" << db->stat());
970
-
971
- // Can not open another connections.
972
- tb2 = db2->openTable(_T("user"));
973
- BOOST_CHECK_MESSAGE(STATUS_CANNOT_LOCK_TABLE == db2->stat(),
974
- "Exclusive opened 2");
975
-
976
- // Can open a same connection.
977
- table* tb3 = db->openTable(_T("user"));
978
- BOOST_CHECK_MESSAGE(0 == db->stat(), "Exclusive opened 2");
979
-
980
- tb->close();
981
- if (tb2 != NULL)
982
- tb2->close();
983
- tb3->close();
984
- db->close();
985
- db2->close();
986
- db->release();
987
- db2->release();
988
- // reopen and update
989
- db = database::create();
990
- tb = openTable(db);
991
-
992
- tb->setKeyNum(0);
993
- tb->seekFirst();
994
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
995
-
996
- tb->setFV(fdi_name, _T("ABC123"));
997
- tb->update();
998
- BOOST_CHECK_MESSAGE(0 == tb->stat(), "update");
999
-
1916
+ db2->open(makeUri(PROTOCOL, HOSTNAME, DBNAME, BDFNAME), TYPE_SCHEMA_BDF);
1917
+ BOOST_CHECK_MESSAGE(0 == db2->stat(), "db2->open");
1918
+ table* tb2 = db2->openTable(_T("user"));
1919
+ {
1920
+ boost::scoped_ptr<worker> w(new worker(tb2));
1921
+
1922
+ // Inserting target, The InnoDB is good!
1923
+ tb->setFV(fdi_id, 300000);
1924
+ tb2->setFV(fdi_id, 300000);
1925
+ tb->seekLessThan(false, ROW_LOCK_X);
1926
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLessThan");
1927
+ if (tb->stat() == 0)
1928
+ {
1929
+ // Get lock(X) same record in parallel.
1930
+ boost::scoped_ptr<boost::thread> t(new boost::thread(boost::bind(&worker::run, w.get())));
1931
+ int v = tb->getFVint(fdi_id);
1932
+ tb->setFV(fdi_id, ++v);
1933
+ tb->insert();
1934
+ t->join();
1935
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->insert");
1936
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLessThan");
1937
+ int v2 = tb2->getFVint(fdi_id);
1938
+ BOOST_CHECK_MESSAGE(v == v2 , "value v = " << v
1939
+ << " bad = " << v2);
1940
+ tb2->unlock();
1941
+ }
1942
+
1943
+ // Deleting target, The InnoDB is good!
1944
+ tb->setFV(fdi_id, 300000);
1945
+ tb2->setFV(fdi_id, 300000);
1946
+ tb->seekLessThan(false, ROW_LOCK_X);
1947
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekLessThan");
1948
+ if (tb->stat() == 0)
1949
+ {
1950
+ // Get lock(X) same record in parallel.
1951
+ boost::scoped_ptr<boost::thread> t(new boost::thread(boost::bind(&worker::run, w.get())));
1952
+ int v = tb->getFVint(fdi_id);
1953
+ tb->del();
1954
+ t->join();
1955
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->insert");
1956
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekLessThan");
1957
+ int v2 = tb2->getFVint(fdi_id);
1958
+ BOOST_CHECK_MESSAGE(v != v2 , "value v = " << v
1959
+ << " bad = " << v2);
1960
+ tb2->unlock();
1961
+ }
1962
+ }
1000
1963
  tb->release();
1001
- db->release();
1964
+ tb2->release();
1965
+ database::destroy(db2);
1002
1966
  }
1003
1967
 
1004
1968
  void testInsert2(database* db)
@@ -1109,7 +2073,7 @@ void testLogin(database* db)
1109
2073
  database* db2 = database::create();
1110
2074
  db2->connect(makeUri(PROTOCOL, HOSTNAME, _T("")), true);
1111
2075
  BOOST_CHECK_MESSAGE(
1112
- 0 == db->stat(),
2076
+ 0 == db2->stat(),
1113
2077
  "new connection connect db->stat() = " << db->stat());
1114
2078
  database::destroy(db2);
1115
2079
 
@@ -2015,9 +2979,15 @@ void doTestSF(table* tb)
2015
2979
  tb->clearBuffer();
2016
2980
 
2017
2981
  tb->setFilter(_T("name = 'あい*'"), 0, 10);
2982
+
2018
2983
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1");
2984
+
2019
2985
  tb->seekFirst();
2020
2986
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1");
2987
+ /*
2988
+ If this point segmentation fult. Then drop database teststring.
2989
+ */
2990
+
2021
2991
  tb->findNext(false);
2022
2992
  BOOST_CHECK_MESSAGE(0 == tb->stat(), "doTestReadSF1");
2023
2993
  BOOST_CHECK_MESSAGE(_tstring(_T("あいうえおかきくこ")) ==
@@ -2139,9 +3109,23 @@ void doTestStringFileter(database* db, int id, const _TCHAR* name,
2139
3109
  tb->release();
2140
3110
  }
2141
3111
 
3112
+ void testDropDataBaseStr(database* db)
3113
+ {
3114
+ db->open(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME), 0, 0);
3115
+ BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase 1");
3116
+ db->drop();
3117
+ BOOST_CHECK_MESSAGE(0 == db->stat(),
3118
+ "DropDataBaseTestString stat=" << db->stat());
3119
+ }
3120
+
2142
3121
  void testStringFileter(database* db)
2143
3122
  {
2144
3123
  db->create(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME));
3124
+ if (db->stat() == STATUS_TABLE_EXISTS_ERROR)
3125
+ {
3126
+ testDropDataBaseStr(db);
3127
+ db->create(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME));
3128
+ }
2145
3129
  BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase");
2146
3130
 
2147
3131
  db->open(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME), 0, 0);
@@ -2160,14 +3144,7 @@ void testStringFileter(database* db)
2160
3144
  db->close();
2161
3145
  }
2162
3146
 
2163
- void testDropDataBaseStr(database* db)
2164
- {
2165
- db->open(makeUri(PROTOCOL, HOSTNAME, _T("testString"), BDFNAME), 0, 0);
2166
- BOOST_CHECK_MESSAGE(0 == db->stat(), "createNewDataBase 1");
2167
- db->drop();
2168
- BOOST_CHECK_MESSAGE(0 == db->stat(),
2169
- "DropDataBaseTestString stat=" << db->stat());
2170
- }
3147
+
2171
3148
  // ------------------------------------------------------------------------
2172
3149
 
2173
3150
  _TCHAR dbNmae[50] = { _T("テスト") };
@@ -2331,7 +3308,7 @@ void testResultField(database* db)
2331
3308
  BOOST_CHECK_MESSAGE(rf.len == 33, " resultField.setParam");
2332
3309
  BOOST_CHECK_MESSAGE(rf.pos == 4, " resultField.setParam");
2333
3310
 
2334
- size_t len = rf.writeBuffer(0, true) - (unsigned char*)0;
3311
+ size_t len = rf.size();
2335
3312
  BOOST_CHECK_MESSAGE(len == 4, " resultField.writeBuffer");
2336
3313
  tb->release();
2337
3314
  }
@@ -2344,7 +3321,7 @@ void testResultDef()
2344
3321
  BOOST_CHECK_MESSAGE(rd.maxRows == 0, " resultDef.maxRows");
2345
3322
  BOOST_CHECK_MESSAGE(rd.fieldCount == 0, " resultDef.fieldCount");
2346
3323
 
2347
- size_t len = rd.writeBuffer(0, true) - (unsigned char*)0;
3324
+ size_t len = rd.size();
2348
3325
  BOOST_CHECK_MESSAGE(len == 4, " resultDef.writeBuffer");
2349
3326
  }
2350
3327
 
@@ -2362,7 +3339,7 @@ void testLogic(database* db)
2362
3339
  BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr");
2363
3340
  BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "abc") == 0, " logic.data");
2364
3341
 
2365
- size_t len = lc.writeBuffer(0, true, false) - (unsigned char*)0;
3342
+ int len = lc.size();
2366
3343
  BOOST_CHECK_MESSAGE(len == 7 + 33, " logic.writeBuffer");
2367
3344
 
2368
3345
  // compField invalid filed name
@@ -2379,7 +3356,7 @@ void testLogic(database* db)
2379
3356
  " logic.logType compField");
2380
3357
  BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr");
2381
3358
  BOOST_CHECK_MESSAGE(*((short*)lc.data) == 0, " logic.data");
2382
- len = lc.writeBuffer(0, true, false) - (unsigned char*)0;
3359
+ len = lc.size();
2383
3360
  BOOST_CHECK_MESSAGE(len == 7 + 2, " logic.writeBuffer");
2384
3361
 
2385
3362
  // invalid filed name
@@ -2395,14 +3372,14 @@ void testLogic(database* db)
2395
3372
  BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic.opr");
2396
3373
  BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "abc") == 0, " logic.data");
2397
3374
 
2398
- len = lc.writeBuffer(0, true, false) - (unsigned char*)0;
3375
+ len = lc.size();
2399
3376
  BOOST_CHECK_MESSAGE(len == 7 + 3, " logic.writeBuffer");
2400
3377
 
2401
3378
  lc.setParam(tb, _T("name"), _T("="), _T("漢字*"), eCend, false);
2402
3379
  BOOST_CHECK_MESSAGE(strcmp((char*)lc.data, "漢字") == 0, " logic.data");
2403
3380
 
2404
- len = lc.writeBuffer(0, true, false) - (unsigned char*)0;
2405
- BOOST_CHECK_MESSAGE(len == 7 + (_tcslen(_T("漢字")) * sizeof(_TCHAR)),
3381
+ len = lc.size();
3382
+ BOOST_CHECK_MESSAGE(len == (int)(7 + (_tcslen(_T("漢字")) * sizeof(_TCHAR))),
2406
3383
  " logic.writeBuffer len =" << len);
2407
3384
 
2408
3385
  // combine
@@ -2451,8 +3428,16 @@ void testLogic(database* db)
2451
3428
 
2452
3429
  BOOST_CHECK_MESSAGE(lc.opr == eCend, " logic joinAfter");
2453
3430
 
3431
+ // placeHolder
3432
+ lc.setParam(tb, _T("name"), _T("="), _T("?"), eCand);
3433
+ BOOST_CHECK_MESSAGE(lc.placeHolder == true, " logic placeHolder");
3434
+
3435
+ lc.setValue(tb, _T("abc*"));
3436
+ BOOST_CHECK_MESSAGE(strcmp((const char*)lc.data, "abc") == 0, "logic setValue");
3437
+ BOOST_CHECK_MESSAGE(lc.len == 3, "logic setValue");
3438
+
2454
3439
  header hd;
2455
- len = hd.writeBuffer(0, true) - (unsigned char*)0;
3440
+ len = hd.size();
2456
3441
  BOOST_CHECK_MESSAGE(len == 8, " header.writeBuffer");
2457
3442
  tb->release();
2458
3443
  }
@@ -2773,7 +3758,7 @@ void teetNewDelete(database* db)
2773
3758
  delete r; // All OK
2774
3759
  }
2775
3760
 
2776
- // activeTable releaseTable
3761
+ //activeTable releaseTable
2777
3762
  activeTable* at = new activeTable(db, _T("user"));
2778
3763
  at->releaseTable();
2779
3764
  BOOST_CHECK_MESSAGE(at->table() == NULL, " activeTable::releaseTable");
@@ -2795,9 +3780,7 @@ void testJoin(database* db)
2795
3780
  #endif
2796
3781
 
2797
3782
  activeTable atu(db, _T("user"));
2798
-
2799
3783
  activeTable atg(db, _T("groups"));
2800
-
2801
3784
  activeTable ate(db, _T("extention"));
2802
3785
  recordset rs;
2803
3786
  query q;
@@ -2806,14 +3789,16 @@ void testJoin(database* db)
2806
3789
  q.select(_T("id"), _T("name"), _T("group"))
2807
3790
  .where(_T("id"), _T("<="), 15000);
2808
3791
  atu.index(0).keyValue(1).read(rs, q);
2809
- BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size()== 15000");
3792
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size() 15000 bad = " << rs.size());
3793
+ BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 3, " rs.fieldDefs()->size() 3 bad = " << rs.fieldDefs()->size());
2810
3794
 
2811
3795
  // Join extention::comment
2812
3796
  q.reset();
2813
3797
  ate.index(0).join(
2814
3798
  rs, q.select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany),
2815
3799
  _T("id"));
2816
- BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size()== 15000");
3800
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size() 15000 bad = " << rs.size());
3801
+ BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 4, " rs.fieldDefs()->size() 4 bad = " << rs.fieldDefs()->size());
2817
3802
 
2818
3803
  // test reverse
2819
3804
 
@@ -2941,6 +3926,282 @@ void testJoin(database* db)
2941
3926
  groupQuery* q3 = groupQuery::create();
2942
3927
  q3->keyField(_T("group"), _T("id"));
2943
3928
  q3->release();
3929
+ }
3930
+
3931
+ void testPrepareJoin(database* db)
3932
+ {
3933
+ #ifdef LINUX
3934
+ const char* fd_name = "名前";
3935
+ #else
3936
+ #ifdef _UNICODE
3937
+ const wchar_t fd_name[] = { L"名前" };
3938
+ #else
3939
+ char fd_name[30];
3940
+ WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL);
3941
+ #endif
3942
+ #endif
3943
+
3944
+ activeTable atu(db, _T("user"));
3945
+ atu.alias(fd_name, _T("name"));
3946
+
3947
+ activeTable atg(db, _T("groups"));
3948
+ atg.alias(_T("name"), _T("group_name"));
3949
+
3950
+ activeTable ate(db, _T("extention"));
3951
+ recordset rs;
3952
+ query q;
3953
+
3954
+
3955
+ q.select(_T("id"), _T("name"), _T("group")).where(_T("id"), _T("<="), _T("?"));
3956
+ pq_handle pq = atu.prepare(q);
3957
+ atu.index(0).keyValue(1).read(rs, pq, 15000);
3958
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size() 15000 bad = " << rs.size());
3959
+ BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 3, " rs.fieldDefs()->size() 3 bad = " << rs.fieldDefs()->size());
3960
+
3961
+ // Join extention::comment
3962
+ q.reset().select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany);
3963
+ pq = ate.prepare(q);
3964
+ ate.index(0).join(rs, pq, _T("id"));
3965
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size() 15000 bad = " << rs.size());
3966
+ BOOST_CHECK_MESSAGE(rs.fieldDefs()->size() == 4, " rs.fieldDefs()->size() 4 bad = " << rs.fieldDefs()->size());
3967
+
3968
+ // test reverse
3969
+ row& last = rs.reverse().first();
3970
+ BOOST_CHECK_MESSAGE(last[_T("id")].i() == 15000, "last field id == 15000");
3971
+ BOOST_CHECK_MESSAGE(_tstring(last[_T("comment")].c_str()) ==
3972
+ _tstring(_T("15000 comment")),
3973
+ "last field comment");
3974
+ // Join group::name
3975
+ q.reset().select(_T("group_name"));
3976
+ pq = atg.prepare(q);
3977
+ atg.index(0).join(rs, pq, _T("group"));
3978
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000");
3979
+ row& first = rs.last();
3980
+
3981
+ BOOST_CHECK_MESSAGE(first[_T("id")].i() == 1, "first field id == 1");
3982
+ BOOST_CHECK_MESSAGE(_tstring(first[_T("comment")].c_str()) ==
3983
+ _tstring(_T("1 comment")),
3984
+ "first field comment");
3985
+
3986
+ BOOST_CHECK_MESSAGE(
3987
+ _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")),
3988
+ "first field group_name " << string(first[_T("group_name")].a_str()));
3989
+ BOOST_CHECK_MESSAGE(
3990
+ _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")),
3991
+ "first field group_name " << string(first[_T("group_name")].a_str()));
3992
+ // row_ptr row = rs[15000 - 9];
3993
+ row& rec = rs[15000 - 9];
3994
+ BOOST_CHECK_MESSAGE(
3995
+ _tstring(rec[_T("group_name")].c_str()) == _tstring(_T("4 group")),
3996
+ "group_name = 4 group " << string((rec)[_T("group_name")].a_str()));
3997
+
3998
+ }
3999
+
4000
+ void testServerPrepareJoin(database* db)
4001
+ {
4002
+ #ifdef LINUX
4003
+ const char* fd_name = "名前";
4004
+ #else
4005
+ #ifdef _UNICODE
4006
+ const wchar_t fd_name[] = { L"名前" };
4007
+ #else
4008
+ char fd_name[30];
4009
+ WideCharToMultiByte(CP_UTF8, 0, L"名前", -1, fd_name, 30, NULL, NULL);
4010
+ #endif
4011
+ #endif
4012
+
4013
+ activeTable atu(db, _T("user"));
4014
+ activeTable atg(db, _T("groups"));
4015
+ activeTable ate(db, _T("extention"));
4016
+ atu.alias(fd_name, _T("name"));
4017
+ atg.alias(_T("name"), _T("group_name"));
4018
+ query q;
4019
+ q.select(_T("id"), _T("name"), _T("group"))
4020
+ .where(_T("id"), _T("<="), _T("?"));
4021
+ pq_handle stmt1 = atu.prepare(q, true);
4022
+ BOOST_CHECK_MESSAGE(stmt1 != NULL, " stmt1");
4023
+
4024
+ q.reset().select(_T("comment")).optimize(queryBase::joinHasOneOrHasMany);
4025
+ pq_handle stmt2 = ate.prepare(q, true);
4026
+ BOOST_CHECK_MESSAGE(stmt2 != NULL, " stmt2");
4027
+
4028
+ q.reset().select(_T("group_name"));
4029
+ pq_handle stmt3 = atg.prepare(q, true);
4030
+ BOOST_CHECK_MESSAGE(stmt3 != NULL, " stmt3");
4031
+
4032
+ recordset rs;
4033
+ atu.index(0).keyValue(1).read(rs, stmt1, 15000);
4034
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, " rs.size()== 15000 bad " << rs.size());
4035
+
4036
+ // Join extention::comment
4037
+ ate.index(0).join(rs, stmt2, _T("id"));
4038
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size()== 15000");
4039
+
4040
+ // test reverse
4041
+ row& last = rs.reverse().first();
4042
+ BOOST_CHECK_MESSAGE(last[_T("id")].i() == 15000, "last field id == 15000");
4043
+ BOOST_CHECK_MESSAGE(_tstring(last[_T("comment")].c_str()) ==
4044
+ _tstring(_T("15000 comment")),
4045
+ "last field comment");
4046
+
4047
+ // Join group::name
4048
+ atg.index(0).join(rs, stmt3, _T("group"));
4049
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000");
4050
+ row& first = rs.last();
4051
+
4052
+ BOOST_CHECK_MESSAGE(first[_T("id")].i() == 1, "first field id == 1");
4053
+ BOOST_CHECK_MESSAGE(_tstring(first[_T("comment")].c_str()) ==
4054
+ _tstring(_T("1 comment")),
4055
+ "first field comment");
4056
+
4057
+ BOOST_CHECK_MESSAGE(
4058
+ _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")),
4059
+ "first field group_name " << string(first[_T("group_name")].a_str()));
4060
+ BOOST_CHECK_MESSAGE(
4061
+ _tstring(first[_T("group_name")].c_str()) == _tstring(_T("1 group")),
4062
+ "first field group_name " << string(first[_T("group_name")].a_str()));
4063
+ // row_ptr row = rs[15000 - 9];
4064
+ row& rec = rs[15000 - 9];
4065
+ BOOST_CHECK_MESSAGE(
4066
+ _tstring(rec[_T("group_name")].c_str()) == _tstring(_T("4 group")),
4067
+ "group_name = 4 group " << string((rec)[_T("group_name")].a_str()));
4068
+
4069
+ // Test orderby
4070
+ rs.orderBy(_T("group_name"));
4071
+ // rec = rs[(size_t)0];
4072
+ BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) ==
4073
+ _tstring(_T("1 group")),
4074
+ "group_name = 1 group "
4075
+ << string(rs[(size_t)0][_T("group_name")].a_str()));
4076
+
4077
+ sortFields orderRv;
4078
+ orderRv.add(_T("group_name"), false);
4079
+ rs.orderBy(orderRv);
4080
+
4081
+ sortFields order;
4082
+ order.add(_T("group_name"), true);
4083
+ rs.orderBy(order);
4084
+ BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0][_T("group_name")].c_str()) ==
4085
+ _tstring(_T("1 group")),
4086
+ "group_name = 1 group "
4087
+ << string(rs[(size_t)0][_T("group_name")].a_str()));
4088
+
4089
+ //All fields
4090
+ rs.clear();
4091
+ q.reset().all();
4092
+ q.where(_T("id"), _T("<="), _T("?"));
4093
+ stmt1 = atu.prepare(q, true);
4094
+ atu.keyValue(1).read(rs, stmt1, 15000);
4095
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "read rs.size()== 15000");
4096
+ if (rs.size() == 15000)
4097
+ {
4098
+ for (int i=0;i<15000;++i)
4099
+ BOOST_CHECK_MESSAGE(rs[i][_T("id")].i() == i+1, "All fields field Value");
4100
+ }
4101
+
4102
+ ate.join(rs, stmt2, _T("id"));
4103
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join rs.size()== 15000");
4104
+ atg.join(rs, stmt3, _T("group"));
4105
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000");
4106
+
4107
+ // OuterJoin
4108
+ #define NO_RECORD_ID 5
4109
+ table_ptr tb = ate.table();
4110
+ tb->setFV(_T("id"), NO_RECORD_ID);
4111
+ tb->seek();
4112
+ if (tb->stat() == 0)
4113
+ tb->del();
4114
+ BOOST_CHECK_MESSAGE(tb->stat() == 0, "ate delete id = 5");
4115
+ q.reset().select(_T("comment"), _T("blob")).optimize(queryBase::joinHasOneOrHasMany);
4116
+ stmt2 = ate.prepare(q, true);
4117
+
4118
+ // Join is remove record(s) no join target record.
4119
+ rs.clear();
4120
+ atu.keyValue(1).read(rs, stmt1, 15000);
4121
+ ate.join(rs, stmt2, _T("id"));
4122
+ BOOST_CHECK_MESSAGE(rs.size() == 14999, "join rs.size()== 14999");
4123
+ BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1][_T("comment")].i() == NO_RECORD_ID+1, "row of 5 : '6 comment'");
4124
+ const _TCHAR* vs = rs[NO_RECORD_ID-1][_T("blob")].c_str();
4125
+ bool ret = _tcscmp(vs, _T("6 blob")) == 0;
4126
+ BOOST_CHECK_MESSAGE(ret == true, "row of 5 : '6 blob'" );
4127
+
4128
+ // OuterJoin is no remove record(s) no join target record.
4129
+ rs.clear();
4130
+ atu.keyValue(1).read(rs, stmt1, 15000);
4131
+ ate.outerJoin(rs, stmt2, _T("id"));
4132
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "outerJoin rs.size()== 15000");
4133
+ atg.outerJoin(rs, stmt3, _T("group"));
4134
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "join2 rs.size()== 15000");
4135
+
4136
+ BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord");
4137
+ BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'");
4138
+ vs = rs[NO_RECORD_ID][_T("blob")].c_str();
4139
+ ret = _tcscmp(vs, _T("6 blob")) == 0;
4140
+ BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'");
4141
+
4142
+ // OuterJoin All Join fields
4143
+ q.reset().optimize(queryBase::joinHasOneOrHasMany).all();
4144
+ stmt2 = ate.prepare(q, true);
4145
+ rs.clear();
4146
+ atu.keyValue(1).read(rs, stmt1, 15000);
4147
+ ate.outerJoin(rs, stmt2, _T("id"));
4148
+ BOOST_CHECK_MESSAGE(rs.size() == 15000, "outerJoin rs.size()== 15000");
4149
+ BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord");
4150
+ BOOST_CHECK_MESSAGE(rs[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'");
4151
+ vs = rs[NO_RECORD_ID][_T("blob")].c_str();
4152
+ ret = _tcscmp(vs, _T("6 blob")) == 0;
4153
+ BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'");
4154
+
4155
+ // Test clone blob field
4156
+ recordset& rs2 = *rs.clone();
4157
+ BOOST_CHECK_MESSAGE(rs2.size() == 15000, "outerJoin rs2.size()== 15000");
4158
+ BOOST_CHECK_MESSAGE(rs2[NO_RECORD_ID-1].isInvalidRecord() == true, "outerJoin isInvalidRecord");
4159
+ BOOST_CHECK_MESSAGE(rs2[NO_RECORD_ID][_T("comment")].i() == NO_RECORD_ID+1, "row of 6 = '6 comment'");
4160
+ vs = rs2[NO_RECORD_ID][_T("blob")].c_str();
4161
+ ret = _tcscmp(vs, _T("6 blob")) == 0;
4162
+ BOOST_CHECK_MESSAGE(ret == true, "row of 6 = '6 blob'");
4163
+
4164
+
4165
+
4166
+
4167
+ //hasManyJoin inner
4168
+ rs.clear();
4169
+ q.reset().reject(0xFFFF).limit(0).all();
4170
+ atg.keyValue(1).read(rs, q);
4171
+ BOOST_CHECK_MESSAGE(rs.size() == 100, "hasManyJoin rs.size()== 100");
4172
+ q.all().optimize(queryBase::joinHasOneOrHasMany);
4173
+ atu.index(1).join(rs, q, _T("code"));
4174
+ BOOST_CHECK_MESSAGE(rs.size() == 20000, "hasManyJoin rs.size()== 20000");
4175
+
4176
+ //hasManyJoin outer
4177
+ rs.clear();
4178
+ q.reset().reject(0xFFFF).limit(0).all();
4179
+ atg.keyValue(1).read(rs, q);
4180
+ BOOST_CHECK_MESSAGE(rs.size() == 100, "hasManyJoin rs.size()== 100");
4181
+ q.all().optimize(queryBase::joinHasOneOrHasMany);
4182
+ atu.index(1).outerJoin(rs, q, _T("code"));
4183
+ BOOST_CHECK_MESSAGE(rs.size() == 20095, "hasManyJoin rs.size()== 20095");
4184
+
4185
+
4186
+ // restore record
4187
+ tb->clearBuffer();
4188
+ tb->setFV(_T("id"), NO_RECORD_ID);
4189
+ tb->setFV(_T("comment"), _T("5 comment"));
4190
+ tb->setFV(_T("blob"), _T("5 blob"));
4191
+ tb->insert();
4192
+ BOOST_CHECK_MESSAGE(tb->stat() == 0, "ate insert id = 5");
4193
+ if (tb->stat())
4194
+ {
4195
+ atu.release();
4196
+ atg.release();
4197
+ ate.release();
4198
+ db->drop();
4199
+ }
4200
+
4201
+
4202
+
4203
+
4204
+
2944
4205
  }
2945
4206
 
2946
4207
  void testWirtableRecord(database* db)
@@ -3021,9 +4282,37 @@ void testDbPool()
3021
4282
 
3022
4283
  connectParams pm(PROTOCOL, HOSTNAME, _T("querytest"), DBNAME);
3023
4284
  poolMgr.use(&pm);
4285
+ BOOST_CHECK_MESSAGE(1 == poolMgr.usingCount(), "usingCount 1");
3024
4286
  poolMgr.use(&pm);
4287
+ BOOST_CHECK_MESSAGE(2 == poolMgr.usingCount(), "usingCount 2");
3025
4288
  poolMgr.use(&pm);
4289
+ BOOST_CHECK_MESSAGE(3 == poolMgr.usingCount(), "usingCount 3");
3026
4290
  poolMgr.unUse();
4291
+ BOOST_CHECK_MESSAGE(0 == poolMgr.usingCount(), "usingCount 0");
4292
+
4293
+ //snapshot method
4294
+ {
4295
+ poolMgr.use(&pm);
4296
+ table_ptr tb2 = openTable(poolMgr.db(), _T("user"));
4297
+
4298
+ poolMgr.use(&pm);
4299
+ table_ptr tb = openTable(poolMgr.db(), _T("user"));
4300
+
4301
+
4302
+ poolMgr.beginSnapshot(MULTILOCK_GAP_SHARE);
4303
+ tb->seekFirst();
4304
+ BOOST_CHECK_MESSAGE(0 == tb->stat(), "tb->seekFirst");
4305
+
4306
+ tb2->seekFirst(ROW_LOCK_X);
4307
+ BOOST_CHECK_MESSAGE(STATUS_LOCK_ERROR == tb2->stat(),
4308
+ "tb2->seekFirst tb2 stat = " << tb2->stat());
4309
+
4310
+ poolMgr.endSnapshot();
4311
+
4312
+ tb2->seekFirst(ROW_LOCK_X);
4313
+ BOOST_CHECK_MESSAGE(0 == tb2->stat(), "tb2->seekFirst");
4314
+ }
4315
+ poolMgr.endSnapshot();
3027
4316
  poolMgr.reset(0);
3028
4317
  }
3029
4318
 
@@ -3062,6 +4351,8 @@ BOOST_FIXTURE_TEST_CASE(findNext, fixture)
3062
4351
  {
3063
4352
  testFindNext(db());
3064
4353
  testFindIn(db());
4354
+ testPrepare(db());
4355
+ testPrepareServer(db());
3065
4356
  }
3066
4357
 
3067
4358
  BOOST_FIXTURE_TEST_CASE(getPercentage, fixture)
@@ -3121,7 +4412,7 @@ BOOST_FIXTURE_TEST_CASE(update, fixture)
3121
4412
 
3122
4413
  BOOST_FIXTURE_TEST_CASE(snapShot, fixture)
3123
4414
  {
3124
- testSnapShot(db());
4415
+ testSnapshot(db());
3125
4416
  }
3126
4417
 
3127
4418
  BOOST_FIXTURE_TEST_CASE(conflict, fixture)
@@ -3129,9 +4420,24 @@ BOOST_FIXTURE_TEST_CASE(conflict, fixture)
3129
4420
  testConflict(db());
3130
4421
  }
3131
4422
 
4423
+ BOOST_FIXTURE_TEST_CASE(transactionLockRepeatable, fixture)
4424
+ {
4425
+ testTransactionLockRepeatable(db());
4426
+ }
4427
+
3132
4428
  BOOST_FIXTURE_TEST_CASE(transactionLock, fixture)
3133
4429
  {
3134
- testTransactionLock(db());
4430
+ testTransactionLockReadCommited(db());
4431
+ }
4432
+
4433
+ BOOST_FIXTURE_TEST_CASE(RecordLock, fixture)
4434
+ {
4435
+ testRecordLock(db());
4436
+ }
4437
+
4438
+ BOOST_FIXTURE_TEST_CASE(MultiDatabase, fixture)
4439
+ {
4440
+ testMultiDatabase(db());
3135
4441
  }
3136
4442
 
3137
4443
  BOOST_AUTO_TEST_CASE(Exclusive)
@@ -3139,6 +4445,11 @@ BOOST_AUTO_TEST_CASE(Exclusive)
3139
4445
  testExclusive();
3140
4446
  }
3141
4447
 
4448
+ BOOST_FIXTURE_TEST_CASE(MissingUpdate, fixture)
4449
+ {
4450
+ testMissingUpdate(db());
4451
+ }
4452
+
3142
4453
  BOOST_FIXTURE_TEST_CASE(insert2, fixture)
3143
4454
  {
3144
4455
  testInsert2(db());
@@ -3234,7 +4545,7 @@ BOOST_FIXTURE_TEST_CASE(dropDataBaseVar, fixture)
3234
4545
 
3235
4546
  BOOST_AUTO_TEST_SUITE_END()
3236
4547
  // ------------------------------------------------------------------------
3237
-
4548
+ #ifdef TDAP
3238
4549
  // ------------------------------------------------------------------------
3239
4550
  BOOST_AUTO_TEST_SUITE(filter)
3240
4551
 
@@ -3250,7 +4561,7 @@ BOOST_FIXTURE_TEST_CASE(dropDataBaseStr, fixture)
3250
4561
 
3251
4562
  BOOST_AUTO_TEST_SUITE_END()
3252
4563
  // ------------------------------------------------------------------------
3253
-
4564
+ #endif
3254
4565
  // ------------------------------------------------------------------------
3255
4566
  BOOST_AUTO_TEST_SUITE(kanjiSchema)
3256
4567
 
@@ -3307,6 +4618,8 @@ BOOST_FIXTURE_TEST_CASE(new_delete, fixtureQuery)
3307
4618
  BOOST_FIXTURE_TEST_CASE(join, fixtureQuery)
3308
4619
  {
3309
4620
  testJoin(db());
4621
+ testPrepareJoin(db());
4622
+ testServerPrepareJoin(db());
3310
4623
  testWirtableRecord(db());
3311
4624
  }
3312
4625