transactd 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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