transactd 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/BUILD_UNIX-JA +6 -6
  3. data/README +16 -16
  4. data/README-JA +16 -16
  5. data/bin/common/tdclc_32_2_1.dll +0 -0
  6. data/bin/common/tdclc_64_2_1.dll +0 -0
  7. data/build/common/transactd_cl_common.cmake +0 -1
  8. data/build/common/transactd_common.cmake +28 -38
  9. data/build/swig/ruby/ruby.swg +36 -30
  10. data/build/swig/ruby/tdclrb_wrap.cpp +35016 -0
  11. data/build/swig/tdcl.i +217 -62
  12. data/build/tdclc/CMakeLists.txt +14 -26
  13. data/build/tdclc/libtdclcm.map +4 -0
  14. data/build/tdclc/tdclc.cbproj +1 -1
  15. data/build/tdclc/tdclc.rc +0 -0
  16. data/build/tdclcpp/CMakeLists.txt +7 -22
  17. data/build/tdclcpp/tdclcpp.rc +0 -0
  18. data/build/tdclcpp/tdclcpp_bc.cbproj +1 -1
  19. data/build/tdclrb/CMakeLists.txt +7 -49
  20. data/build/tdclrb/tdclrb.rc +62 -0
  21. data/source/bzs/db/blobBuffer.h +5 -0
  22. data/source/bzs/db/blobStructs.h +2 -0
  23. data/source/bzs/db/engine/mysql/IReadRecords.h +9 -0
  24. data/source/bzs/db/engine/mysql/database.cpp +391 -169
  25. data/source/bzs/db/engine/mysql/database.h +178 -40
  26. data/source/bzs/db/engine/mysql/dbManager.cpp +45 -3
  27. data/source/bzs/db/engine/mysql/dbManager.h +3 -39
  28. data/source/bzs/db/engine/mysql/errorMessage.cpp +11 -7
  29. data/source/bzs/db/engine/mysql/errorMessage.h +1 -1
  30. data/source/bzs/db/engine/mysql/mydebuglog.cpp +1 -2
  31. data/source/bzs/db/engine/mysql/mysqlInternal.h +8 -8
  32. data/source/bzs/db/engine/mysql/mysqlThd.cpp +11 -0
  33. data/source/bzs/db/protocol/hs/hsCommandExecuter.cpp +1 -1
  34. data/source/bzs/db/protocol/tdap/client/activeTable.cpp +41 -6
  35. data/source/bzs/db/protocol/tdap/client/activeTable.h +177 -8
  36. data/source/bzs/db/protocol/tdap/client/activeTableImple.h +141 -62
  37. data/source/bzs/db/protocol/tdap/client/client.cpp +39 -35
  38. data/source/bzs/db/protocol/tdap/client/client.h +52 -25
  39. data/source/bzs/db/protocol/tdap/client/connectionPool.cpp +17 -0
  40. data/source/bzs/db/protocol/tdap/client/connectionPool.h +1 -0
  41. data/source/bzs/db/protocol/tdap/client/database.cpp +5 -1
  42. data/source/bzs/db/protocol/tdap/client/database.h +1 -1
  43. data/source/bzs/db/protocol/tdap/client/databaseFactory.cpp +49 -12
  44. data/source/bzs/db/protocol/tdap/client/databaseManager.h +42 -5
  45. data/source/bzs/db/protocol/tdap/client/dbDef.cpp +4 -2
  46. data/source/bzs/db/protocol/tdap/client/dllmain.cpp +71 -41
  47. data/source/bzs/db/protocol/tdap/client/errorMessage_ja.cpp +49 -49
  48. data/source/bzs/db/protocol/tdap/client/field.cpp +22 -13
  49. data/source/bzs/db/protocol/tdap/client/field.h +7 -3
  50. data/source/bzs/db/protocol/tdap/client/fieldDDF.cpp +1 -1
  51. data/source/bzs/db/protocol/tdap/client/fieldNameAlias.cpp +0 -1
  52. data/source/bzs/db/protocol/tdap/client/fieldNameAlias.h +1 -0
  53. data/source/bzs/db/protocol/tdap/client/fields.h +111 -24
  54. data/source/bzs/db/protocol/tdap/client/fileDDF.cpp +1 -1
  55. data/source/bzs/db/protocol/tdap/client/filter.h +687 -310
  56. data/source/bzs/db/protocol/tdap/client/groupQuery.cpp +12 -4
  57. data/source/bzs/db/protocol/tdap/client/indexDDF.cpp +1 -1
  58. data/source/bzs/db/protocol/tdap/client/memRecord.cpp +190 -32
  59. data/source/bzs/db/protocol/tdap/client/memRecord.h +64 -22
  60. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +4 -4
  61. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +4 -2
  62. data/source/bzs/db/protocol/tdap/client/nsTable.cpp +6 -3
  63. data/source/bzs/db/protocol/tdap/client/nsTable.h +1 -1
  64. data/source/bzs/db/protocol/tdap/client/pooledDatabaseManager.h +19 -8
  65. data/source/bzs/db/protocol/tdap/client/recordsetImple.h +194 -87
  66. data/source/bzs/db/protocol/tdap/client/request.h +84 -26
  67. data/source/bzs/db/protocol/tdap/client/stringConverter.h +22 -12
  68. data/source/bzs/db/protocol/tdap/client/table.cpp +494 -286
  69. data/source/bzs/db/protocol/tdap/client/table.h +48 -5
  70. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +133 -87
  71. data/source/bzs/db/protocol/tdap/client/trdboostapiInternal.h +22 -22
  72. data/source/bzs/db/protocol/tdap/client/trdormapi.h +43 -18
  73. data/source/bzs/db/protocol/tdap/client/trnsctcl.def +3 -3
  74. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.cpp +1 -0
  75. data/source/bzs/db/protocol/tdap/mysql/recordsetReader.h +268 -74
  76. data/source/bzs/db/protocol/tdap/mysql/request.h +4 -4
  77. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +179 -43
  78. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.h +4 -4
  79. data/source/bzs/db/protocol/tdap/tdapRequest.h +15 -14
  80. data/source/bzs/db/protocol/tdap/tdapSchema.h +125 -90
  81. data/source/bzs/db/protocol/tdap/tdapcapi.h +46 -5
  82. data/source/bzs/db/transactd/appModule.h +1 -1
  83. data/source/bzs/db/transactd/connManager.cpp +2 -0
  84. data/source/bzs/db/transactd/transactd.cpp +1 -0
  85. data/source/bzs/env/compiler.h +10 -0
  86. data/source/bzs/env/mbcswchrLinux.cpp +42 -6
  87. data/source/bzs/env/mbcswchrLinux.h +40 -12
  88. data/source/bzs/example/queryData.cpp +33 -4
  89. data/source/bzs/netsvc/client/iconnection.h +107 -0
  90. data/source/bzs/netsvc/client/tcpClient.cpp +15 -1
  91. data/source/bzs/netsvc/client/tcpClient.h +96 -87
  92. data/source/bzs/netsvc/server/serverCpt.cpp +5 -6
  93. data/source/bzs/rtl/benchmark.cpp +2 -2
  94. data/source/bzs/rtl/stringBuffers.cpp +3 -3
  95. data/source/bzs/rtl/stringBuffers.h +2 -2
  96. data/source/bzs/test/tdclatl/bench_query_atl.js +92 -99
  97. data/source/bzs/test/tdclatl/test_query_atl.js +224 -115
  98. data/source/bzs/test/tdclphp/bench.php +126 -101
  99. data/source/bzs/test/tdclphp/transactd_Test.php +1122 -158
  100. data/source/bzs/test/tdclrb/bench_tdclcpp.rb +12 -14
  101. data/source/bzs/test/tdclrb/transactd_spec.rb +1127 -142
  102. data/source/bzs/test/transactdBench/query_bench.cpp +32 -15
  103. data/source/bzs/test/transactdBench/scaling_bench.cpp +32 -7
  104. data/source/bzs/test/transactdBench/transactdBench.cpp +1 -1
  105. data/source/bzs/test/transactdBench/workerBase.h +46 -0
  106. data/source/bzs/test/transactdBench/workerMySQLImple.h +15 -7
  107. data/source/bzs/test/transactdBench/workerTransactdImple.h +10 -18
  108. data/source/bzs/test/trdclengn/test_trdclengn.cpp +1487 -174
  109. data/source/global/ormsrcgen/main.cpp +2 -0
  110. data/source/global/tdclatl/Database.cpp +2 -2
  111. data/source/global/tdclatl/Database.h +1 -1
  112. data/source/global/tdclatl/FieldDefs.cpp +0 -3
  113. data/source/global/tdclatl/PooledDbManager.cpp +2 -2
  114. data/source/global/tdclatl/PooledDbManager.h +1 -1
  115. data/source/global/tdclatl/PreparedQuery.cpp +53 -0
  116. data/source/global/tdclatl/PreparedQuery.h +61 -0
  117. data/source/global/tdclatl/QueryBase.cpp +2 -1
  118. data/source/global/tdclatl/QueryBase.h +1 -1
  119. data/source/global/tdclatl/Record.cpp +3 -15
  120. data/source/global/tdclatl/Recordset.cpp +15 -10
  121. data/source/global/tdclatl/Recordset.h +3 -0
  122. data/source/global/tdclatl/Table.cpp +42 -7
  123. data/source/global/tdclatl/Table.h +3 -1
  124. data/source/global/tdclatl/activeTable.cpp +264 -76
  125. data/source/global/tdclatl/activeTable.h +12 -3
  126. data/source/global/tdclatl/tdclatl.idl +92 -10
  127. data/source/linux/charsetConvert.h +7 -7
  128. data/transactd.gemspec +14 -27
  129. metadata +18 -27
  130. data/bin/common/tdclc_32_2_0.dll +0 -0
  131. data/bin/common/tdclc_64_2_0.dll +0 -0
  132. data/build/swig/php/generate.cmake.in +0 -56
  133. data/build/swig/php/generate.cmd.in +0 -47
  134. data/build/swig/php/php.swg +0 -197
  135. data/build/swig/php/transactd.no_yield.php +0 -4494
  136. data/build/swig/php/transactd.no_yield.php.git.patch +0 -685
  137. data/build/swig/php/transactd.no_yield.php.patch +0 -685
  138. data/build/swig/php/transactd.yield.php +0 -4461
  139. data/build/swig/php/transactd.yield.php.git.patch +0 -652
  140. data/build/swig/php/transactd.yield.php.patch +0 -652
  141. data/build/swig/ruby/generate.cmake.in +0 -35
  142. data/build/swig/ruby/generate.cmd.in +0 -19
  143. data/build/tdclc/BUILDNUMBER.txt +0 -1
  144. data/build/tdclcpp/BUILDNUMBER.txt +0 -1
  145. data/build/tdclrb/BUILDNUMBER.txt +0 -1
  146. data/build/tdclrb/GEM_RELEASE_VERSION +0 -1
@@ -21,16 +21,14 @@ mb_internal_encoding('UTF-8');
21
21
 
22
22
  require_once("transactd.php");
23
23
  use BizStation\Transactd as Bz;
24
-
25
- define('URL', 'tdap://localhost/test_bench?dbfile=test.bdf');
26
24
  define('TABLENAME', 'users');
27
25
  define('FDI_ID', 0);
28
26
  define('FDI_NAME', 1);
29
27
  define('BULKBUFSIZE', 65535 - 1000);
30
-
31
28
  define('RECORD_COUNT', 20000);
32
29
  define('RECORD_UNIT', 20);
33
30
 
31
+
34
32
  function assertEquals($a, $b, $msg = '') {
35
33
  if ($a !== $b) {
36
34
  echo("$a !== $b $msg");
@@ -46,19 +44,19 @@ function assertNotEquals($a, $b, $msg = '') {
46
44
  return true;
47
45
  }
48
46
 
49
- function create($url) {
47
+ function create($URI) {
50
48
  // create database
51
49
  $db = new Bz\database();
52
- $db->create($url);
50
+ $db->create($URI);
53
51
  if ($db->stat() == Bz\transactd::STATUS_TABLE_EXISTS_ERROR) {
54
- $db->open($url);
52
+ $db->open($URI);
55
53
  assertEquals($db->stat(), 0);
56
54
  $db->drop();
57
55
  assertEquals($db->stat(), 0);
58
- $db->create($url);
56
+ $db->create($URI);
59
57
  }
60
58
  assertEquals($db->stat(), 0);
61
- $db->open($url, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
59
+ $db->open($URI, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
62
60
  assertEquals($db->stat(), 0);
63
61
  // create table
64
62
  $dbdef = $db->dbDef();
@@ -124,8 +122,8 @@ function deleteAll($db, $tb) {
124
122
 
125
123
  function insert($db, $tb) {
126
124
  $tb->setKeyNum(0);
125
+ $tb->clearBuffer();
127
126
  for ($i = 1; $i <= RECORD_COUNT; $i++) {
128
- $tb->clearBuffer();
129
127
  $tb->setFV(FDI_ID, $i);
130
128
  $tb->setFV(FDI_NAME, $i);
131
129
  $tb->insert();
@@ -138,15 +136,15 @@ function insert($db, $tb) {
138
136
  function insertTransaction($db, $tb) {
139
137
  $tb->setKeyNum(0);
140
138
  $start = 1;
139
+ $tb->clearBuffer();
141
140
  while ($start < RECORD_COUNT) {
142
141
  $db->beginTrn();
143
142
  for ($i = $start; $i < $start + RECORD_UNIT; $i++) {
144
- $tb->clearBuffer();
145
143
  $tb->setFV(FDI_ID, $i);
146
144
  $tb->setFV(FDI_NAME, $i);
147
145
  $tb->insert();
148
146
  if (!assertEquals($tb->stat(), 0, 'insertTransaction')) {
149
- $db->endTrn();
147
+ $db->abortTrn();
150
148
  return false;
151
149
  }
152
150
  }
@@ -159,10 +157,10 @@ function insertTransaction($db, $tb) {
159
157
  function insertBulk($db, $tb) {
160
158
  $tb->setKeyNum(0);
161
159
  $start = 1;
160
+ $tb->clearBuffer();
162
161
  while ($start < RECORD_COUNT) {
163
162
  $tb->beginBulkInsert(BULKBUFSIZE);
164
163
  for ($i = $start; $i < $start + RECORD_UNIT; $i++) {
165
- $tb->clearBuffer();
166
164
  $tb->setFV(FDI_ID, $i);
167
165
  $tb->setFV(FDI_NAME, $i);
168
166
  $tb->insert();
@@ -179,12 +177,13 @@ function insertBulk($db, $tb) {
179
177
 
180
178
  function read($db, $tb) {
181
179
  $tb->setKeyNum(0);
180
+ $tb->clearBuffer();
182
181
  for ($i = 1; $i <= RECORD_COUNT; $i++) {
183
- $tb->clearBuffer();
184
182
  $tb->setFV(FDI_ID, $i);
185
183
  $tb->seek();
186
- if (!assertEquals($tb->stat(), 0, 'read') ||
187
- !assertEquals($tb->getFVint(FDI_ID), $i, 'read value')) {
184
+ if (($tb->stat() !==0) || ($tb->getFVint(FDI_ID) !== $i))
185
+ {
186
+ echo("seek stat = ".$tb->stat()." value ".$i." = ".$tb->getFVint(FDI_ID));
188
187
  return false;
189
188
  }
190
189
  }
@@ -192,17 +191,17 @@ function read($db, $tb) {
192
191
  }
193
192
 
194
193
  function readSnapshot($db, $tb) {
195
- $ret = true;
196
194
  $tb->setKeyNum(0);
197
195
  $db->beginSnapshot();
196
+ $tb->clearBuffer();
198
197
  for ($i = 1; $i <= RECORD_COUNT; $i++) {
199
- $tb->clearBuffer();
200
198
  $tb->setFV(FDI_ID, $i);
201
199
  $tb->seek();
202
- if (!assertEquals($tb->stat(), 0, 'read') ||
203
- !assertEquals($tb->getFVint(FDI_ID), $i, 'read value')) {
204
- $ret = false;
205
- break;
200
+ if (($tb->stat() !==0) || ($tb->getFVint(FDI_ID) !== $i))
201
+ {
202
+ echo("seek stat = ".$tb->stat()." value ".$i." = ".$tb->getFVint(FDI_ID));
203
+ $db->endSnapshot();
204
+ return false;
206
205
  }
207
206
  }
208
207
  $db->endSnapshot();
@@ -210,16 +209,17 @@ function readSnapshot($db, $tb) {
210
209
  }
211
210
 
212
211
  function readRange($db, $tb) {
213
- $tb->setKeyNum(0);
214
212
  $start = 1;
213
+ $tb->setKeyNum(0);
214
+ $tb->clearBuffer();
215
+ $tb->setFilter('*', 1, RECORD_UNIT);
216
+ $tb->setFV(FDI_ID, $start);
217
+ $tb->find(Bz\table::findForword);
215
218
  while ($start < RECORD_COUNT) {
216
- $tb->clearBuffer();
217
- $tb->setFilter('*', 1, RECORD_UNIT);
218
- $tb->setFV(FDI_ID, $start);
219
- $tb->find(Bz\table::findForword);
220
219
  for ($i = $start; $i < $start + RECORD_UNIT; $i++) {
221
- if (!assertEquals($tb->stat(), 0, 'readRange') ||
222
- !assertEquals($tb->getFVint(FDI_ID), $i, 'readRange value')) {
220
+ if (/*($tb->stat() !==0) || */($tb->getFVint(FDI_ID) !== $i))
221
+ {
222
+ echo("find stat = ".$tb->stat()." value ".$i." = ".$tb->getFVint(FDI_ID));
223
223
  return false;
224
224
  }
225
225
  $tb->findNext();
@@ -230,17 +230,19 @@ function readRange($db, $tb) {
230
230
  }
231
231
 
232
232
  function readRangeSnapshot($db, $tb) {
233
+ $start = 1;
233
234
  $tb->setKeyNum(0);
235
+ $tb->clearBuffer();
236
+ $tb->setFilter('*', 1, RECORD_UNIT);
237
+ $tb->setFV(FDI_ID, $start);
234
238
  $db->beginSnapshot();
235
- $start = 1;
239
+ $tb->find(Bz\table::findForword);
236
240
  while ($start < RECORD_COUNT) {
237
- $tb->clearBuffer();
238
- $tb->setFilter('*', 1, RECORD_UNIT);
239
- $tb->setFV(FDI_ID, $start);
240
- $tb->find(Bz\table::findForword);
241
241
  for ($i = $start; $i < $start + RECORD_UNIT; $i++) {
242
- if (!assertEquals($tb->stat(), 0, 'readRange snapshot') ||
243
- !assertEquals($tb->getFVint(FDI_ID), $i, 'readRange snapshot value')) {
242
+ if (/*($tb->stat() !==0) || */($tb->getFVint(FDI_ID) !== $i))
243
+ {
244
+ echo("find stat = ".$tb->stat()." value ".$i." = ".$tb->getFVint(FDI_ID));
245
+ $db->endSnapshot();
244
246
  return false;
245
247
  }
246
248
  $tb->findNext();
@@ -253,13 +255,16 @@ function readRangeSnapshot($db, $tb) {
253
255
 
254
256
  function update($db, $tb) {
255
257
  $tb->setKeyNum(0);
258
+ $tb->clearBuffer();
256
259
  for ($i = 1; $i <= RECORD_COUNT; $i++) {
257
- $tb->clearBuffer();
258
260
  $tb->setFV(FDI_ID, $i);
259
261
  $tb->setFV(FDI_NAME, ($i + 1));
260
262
  $tb->update(Bz\table::changeInKey);
261
- if (!assertEquals($tb->stat(), 0, 'update'))
263
+ if ($tb->stat() !==0)
264
+ {
265
+ echo("update stat = ".$tb->stat());
262
266
  return false;
267
+ }
263
268
  }
264
269
  return true;
265
270
  }
@@ -267,15 +272,17 @@ function update($db, $tb) {
267
272
  function updateTransaction($db, $tb) {
268
273
  $tb->setKeyNum(0);
269
274
  $start = 1;
275
+ $tb->clearBuffer();
270
276
  while ($start < RECORD_COUNT) {
271
277
  $db->beginTrn();
272
278
  for ($i = $start; $i < $start + RECORD_UNIT; $i++) {
273
- $tb->clearBuffer();
274
279
  $tb->setFV(FDI_ID, $i);
275
280
  $tb->setFV(FDI_NAME, ($i + 2));
276
281
  $tb->update(Bz\table::changeInKey);
277
- if (!assertEquals($tb->stat(), 0, 'updateTransaction')) {
278
- $db->endTrn();
282
+ if ($tb->stat() !==0)
283
+ {
284
+ echo("update stat = ".$tb->stat());
285
+ $db->abortTrn();
279
286
  return false;
280
287
  }
281
288
  }
@@ -285,73 +292,91 @@ function updateTransaction($db, $tb) {
285
292
  return true;
286
293
  }
287
294
 
288
- function main($url) {
289
- Bz\benchmark::start();
290
- create($url);
291
- Bz\benchmark::showTimeSec(true, ': create');
295
+ function main($argc, $argv) {
296
+ if ($argc < 4) {
297
+ echo("usage: php bench.php databaseUri processNumber functionNumber\n");
298
+ echo("\t --- functionNumber list ---\n");
299
+ echo("\t-1: all function\n");
300
+ echo("\t 0: Insert\n");
301
+ echo("\t 1: Insert in transaction. 20rec x 1000times\n");
302
+ echo("\t 2: Insert by bulkmode. 20rec x 1000times\n");
303
+ echo("\t 3: read each record\n");
304
+ echo("\t 4: read each record with snapshot\n");
305
+ echo("\t 5: read range. 20rec x 1000times\n");
306
+ echo("\t 6: read range with snapshpot. 20rec x 1000times\n");
307
+ echo("\t 7: update\n");
308
+ echo("\t 8: update in transaction. 20rec x 1000times\n");
309
+ echo("example : php bench.php \"tdap://localhost/test?dbfile=test.bdf\" 0 -1\n");
310
+ return;
311
+ }
312
+
313
+ $URI = $argv[1];
314
+ // Currenty $proc is ignored.
315
+ $proc = (int)$argv[2];
316
+ $funcNum = (int)$argv[3];
317
+
318
+ create($URI);
319
+ echo("CreateDataBase success.\n");
320
+ echo("Start Bench mark Insert Items = ".RECORD_COUNT."\n");
321
+ echo(date(DATE_ATOM)."\n");
322
+ echo($URI."\n");
323
+ echo("----------------------------------------\n");
292
324
 
293
325
  $db = new Bz\database();
294
- $db->open($url, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
326
+ $db->open($URI, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
295
327
  assertEquals($db->stat(), 0);
296
328
  $tb = $db->openTable(TABLENAME);
297
329
  assertEquals($db->stat(), 0);
298
330
 
299
- echo("--------------------------------\n");
300
-
301
- deleteAll($db, $tb);
302
- Bz\benchmark::start();
303
- $ret = insert($db, $tb);
304
- Bz\benchmark::showTimeSec($ret, ': insert ' . RECORD_COUNT);
305
-
306
- echo("--------------------------------\n");
307
-
308
- deleteAll($db, $tb);
309
- Bz\benchmark::start();
310
- $ret = insertTransaction($db, $tb);
311
- Bz\benchmark::showTimeSec($ret, ': insertTransaction ' . RECORD_COUNT . ' with transaction per ' . RECORD_UNIT);
312
-
313
- echo("--------------------------------\n");
314
-
315
- deleteAll($db, $tb);
316
- Bz\benchmark::start();
317
- $ret = insertBulk($db, $tb);
318
- Bz\benchmark::showTimeSec($ret, ': insertBulk ' . RECORD_COUNT . ' with bulkmode per ' . RECORD_UNIT);
319
-
320
- echo("--------------------------------\n");
321
-
322
- Bz\benchmark::start();
323
- $ret = read($db, $tb);
324
- Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT);
325
-
326
- echo("--------------------------------\n");
327
-
328
- Bz\benchmark::start();
329
- $ret = readSnapshot($db, $tb);
330
- Bz\benchmark::showTimeSec($ret, ': read with snapshot ' . RECORD_COUNT);
331
-
332
- echo("--------------------------------\n");
333
-
334
- Bz\benchmark::start();
335
- $ret = readRange($db, $tb);
336
- Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT . ' with range per ' . RECORD_UNIT);
337
-
338
- echo("--------------------------------\n");
339
-
340
- Bz\benchmark::start();
341
- $ret = readRangeSnapshot($db, $tb);
342
- Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT . ' with snapshot and range per ' . RECORD_UNIT);
343
-
344
- echo("--------------------------------\n");
345
-
346
- Bz\benchmark::start();
347
- $ret = update($db, $tb);
348
- Bz\benchmark::showTimeSec($ret, ': update ' . RECORD_COUNT);
331
+ if (($funcNum === -1) || ($funcNum === 0)) {
332
+ deleteAll($db, $tb);
333
+ Bz\benchmark::start();
334
+ $ret = insert($db, $tb);
335
+ Bz\benchmark::showTimeSec($ret, ': insert ' . RECORD_COUNT);
336
+ }
349
337
 
350
- echo("--------------------------------\n");
338
+ if (($funcNum === -1) || ($funcNum === 1)) {
339
+ deleteAll($db, $tb);
340
+ Bz\benchmark::start();
341
+ $ret = insertTransaction($db, $tb);
342
+ Bz\benchmark::showTimeSec($ret, ': insertTransaction ' . RECORD_COUNT . ' with transaction per ' . RECORD_UNIT);
343
+ }
351
344
 
352
- Bz\benchmark::start();
353
- $ret = updateTransaction($db, $tb);
354
- Bz\benchmark::showTimeSec($ret, ': updateTransaction ' . RECORD_COUNT . ' with transaction per ' . RECORD_UNIT);
345
+ if (($funcNum === -1) || ($funcNum === 2)) {
346
+ deleteAll($db, $tb);
347
+ Bz\benchmark::start();
348
+ $ret = insertBulk($db, $tb);
349
+ Bz\benchmark::showTimeSec($ret, ': insertBulk ' . RECORD_COUNT . ' with bulkmode per ' . RECORD_UNIT);
350
+ }
351
+ if (($funcNum === -1) || ($funcNum === 3)) {
352
+ Bz\benchmark::start();
353
+ $ret = read($db, $tb);
354
+ Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT);
355
+ }
356
+ if (($funcNum === -1) || ($funcNum === 4)) {
357
+ Bz\benchmark::start();
358
+ $ret = readSnapshot($db, $tb);
359
+ Bz\benchmark::showTimeSec($ret, ': read with snapshot ' . RECORD_COUNT);
360
+ }
361
+ if (($funcNum === -1) || ($funcNum === 5)) {
362
+ Bz\benchmark::start();
363
+ $ret = readRange($db, $tb);
364
+ Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT . ' with range per ' . RECORD_UNIT);
365
+ }
366
+ if (($funcNum === -1) || ($funcNum === 6)) {
367
+ Bz\benchmark::start();
368
+ $ret = readRangeSnapshot($db, $tb);
369
+ Bz\benchmark::showTimeSec($ret, ': read ' . RECORD_COUNT . ' with snapshot and range per ' . RECORD_UNIT);
370
+ }
371
+ if (($funcNum === -1) || ($funcNum === 7)) {
372
+ Bz\benchmark::start();
373
+ $ret = update($db, $tb);
374
+ Bz\benchmark::showTimeSec($ret, ': update ' . RECORD_COUNT);
375
+ }
376
+ if (($funcNum === -1) || ($funcNum === 8)) {
377
+ Bz\benchmark::start();
378
+ $ret = updateTransaction($db, $tb);
379
+ Bz\benchmark::showTimeSec($ret, ': updateTransaction ' . RECORD_COUNT . ' with transaction per ' . RECORD_UNIT);
380
+ }
355
381
  }
356
-
357
- main(URL);
382
+ main($argc, $argv);
@@ -44,9 +44,6 @@ define("TEST_COUNT", 20000);
44
44
  define("FIVE_PERCENT_OF_TEST_COUNT", TEST_COUNT / 20);
45
45
  define("ALLOWABLE_ERROR_DISTANCE_IN_ESTIMATE_COUNT", TEST_COUNT / 4);
46
46
 
47
- define("ISOLATION_READ_COMMITTED", true);
48
- define("ISOLATION_REPEATABLE_READ", false);
49
-
50
47
  class transactdTest extends PHPUnit_Framework_TestCase
51
48
  {
52
49
  private function dropDatabase($db)
@@ -84,8 +81,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
84
81
  $td->setFileName(TABLENAME . '.dat');
85
82
  // Set table default charaset index
86
83
  // - default charset for field VALUE
87
- $td->charsetIndex = Bz\transactd::charsetIndex(Bz\transactd::CP_UTF8);
88
- //
84
+ $td->charsetIndex = Bz\transactd::charsetIndex(Bz\transactd::CP_UTF8);
89
85
  $tableid = 1;
90
86
  $td->id = $tableid;
91
87
  $td->pageSize = 2048;
@@ -93,14 +89,14 @@ class transactdTest extends PHPUnit_Framework_TestCase
93
89
  $this->assertEquals($dbdef->stat(), 0);
94
90
 
95
91
  $fd = $dbdef->insertField($tableid, 0);
96
- $fd->setName("id");
92
+ $fd->setName('id');
97
93
  $fd->type = Bz\transactd::ft_integer;
98
94
  $fd->len = 4;
99
95
  $dbdef->updateTableDef($tableid);
100
96
  $this->assertEquals($dbdef->stat(), 0);
101
97
 
102
98
  $fd = $dbdef->insertField($tableid, 1);
103
- $fd->setName("name");
99
+ $fd->setName('name');
104
100
  $fd->type = Bz\transactd::ft_zstring;
105
101
  $fd->len = 33;
106
102
  $dbdef->updateTableDef($tableid);
@@ -110,24 +106,58 @@ class transactdTest extends PHPUnit_Framework_TestCase
110
106
  // $fd->setCharsetIndex(Bz\transactd::charsetIndex(Bz\transactd::CP_UTF8))
111
107
 
112
108
  $fd = $dbdef->insertField($tableid, 2);
113
- $fd->setName("select");
109
+ $fd->setName('select');
114
110
  $fd->type = Bz\transactd::ft_integer;
115
111
  $fd->len = 4;
116
112
  $dbdef->updateTableDef($tableid);
117
113
  $this->assertEquals($dbdef->stat(), 0);
118
114
 
119
115
  $fd = $dbdef->insertField($tableid, 3);
120
- $fd->setName("in");
116
+ $fd->setName('in');
117
+ $fd->type = Bz\transactd::ft_integer;
118
+ $fd->len = 4;
119
+ $dbdef->updateTableDef($tableid);
120
+ $this->assertEquals($dbdef->stat(), 0);
121
+
122
+ $kd = $dbdef->insertKey($tableid, 0);
123
+ $kd->segment(0)->fieldNum = 0;
124
+ $kd->segment(0)->flags->bit8 = 1;
125
+ $kd->segment(0)->flags->bit1 = 1;
126
+ $kd->segmentCount = 1;
127
+ $dbdef->updateTableDef($tableid);
128
+ $this->assertEquals($dbdef->stat(), 0);
129
+
130
+ // group table
131
+ $td = new Bz\tabledef();
132
+ $td->schemaCodePage = Bz\transactd::CP_UTF8;
133
+ $td->setTableName('group');
134
+ $td->setFileName('group.dat');
135
+ $tableid = 2;
136
+ $td->id = $tableid;
137
+ $td->pageSize = 2048;
138
+ $dbdef->insertTable($td);
139
+ $this->assertEquals($dbdef->stat(), 0);
140
+
141
+ $fd = $dbdef->insertField($tableid, 0);
142
+ $fd->setName('id');
121
143
  $fd->type = Bz\transactd::ft_integer;
122
144
  $fd->len = 4;
123
145
  $dbdef->updateTableDef($tableid);
124
146
  $this->assertEquals($dbdef->stat(), 0);
125
147
 
148
+ $fd = $dbdef->insertField($tableid, 1);
149
+ $fd->setName('name');
150
+ $fd->type = Bz\transactd::ft_zstring;
151
+ $fd->len = 33;
152
+ $dbdef->updateTableDef($tableid);
153
+ $this->assertEquals($dbdef->stat(), 0);
154
+
126
155
  $kd = $dbdef->insertKey($tableid, 0);
127
156
  $kd->segment(0)->fieldNum = 0;
128
157
  $kd->segment(0)->flags->bit8 = 1;
129
158
  $kd->segment(0)->flags->bit1 = 1;
130
159
  $kd->segmentCount = 1;
160
+
131
161
  $dbdef->updateTableDef($tableid);
132
162
  $this->assertEquals($dbdef->stat(), 0);
133
163
  }
@@ -285,6 +315,8 @@ class transactdTest extends PHPUnit_Framework_TestCase
285
315
  while ($i < TEST_COUNT)
286
316
  {
287
317
  $this->assertEquals($tb->stat(), 0);
318
+ if ($tb->stat() != 0)
319
+ break;
288
320
  $this->assertEquals($tb->getFVint(FDI_ID), $i);
289
321
  $tb->findNext(true); // 11 - 19
290
322
  $i = $i + 1;
@@ -298,6 +330,8 @@ class transactdTest extends PHPUnit_Framework_TestCase
298
330
  while ($i >= 10)
299
331
  {
300
332
  $this->assertEquals($tb->stat(), 0);
333
+ if ($tb->stat() != 0)
334
+ break;
301
335
  $this->assertEquals($tb->getFVint(FDI_ID), $i);
302
336
  $tb->findPrev(true); // 11 - 19
303
337
  $i = $i - 1;
@@ -324,6 +358,8 @@ class transactdTest extends PHPUnit_Framework_TestCase
324
358
  for ($i = $v + 1; $i <= (TEST_COUNT - 1); $i++)
325
359
  {
326
360
  $tb->findNext(true); // 11 - 19
361
+ if ($tb->stat() != 0)
362
+ break;
327
363
  $this->assertEquals($tb->stat(), 0);
328
364
  $this->assertEquals($tb->getFVint(FDI_ID), $i);
329
365
  }
@@ -370,10 +406,9 @@ class transactdTest extends PHPUnit_Framework_TestCase
370
406
  $this->assertEquals($tb->stat(), Bz\transactd::STATUS_EOF);
371
407
 
372
408
  // Many params
373
- $q->addSeekKeyValue('1', true);
374
- for($i = 2; $i <= 10000; $i++)
409
+ for($i = 1; $i <= 10000; $i++)
375
410
  {
376
- $q->addSeekKeyValue(strval($i));
411
+ $q->addSeekKeyValue(strval($i), ($i == 1)); // reset
377
412
  }
378
413
  $tb->setQuery($q);
379
414
  $this->assertEquals($tb->stat(), 0);
@@ -459,6 +494,8 @@ class transactdTest extends PHPUnit_Framework_TestCase
459
494
  {
460
495
  $tb->seekNext();
461
496
  $this->assertEquals($tb->getFVint(FDI_ID), $i);
497
+ if ($i != $tb->getFVint(FDI_ID))
498
+ break;
462
499
  }
463
500
  $db->endSnapshot();
464
501
  }
@@ -477,10 +514,27 @@ class transactdTest extends PHPUnit_Framework_TestCase
477
514
  {
478
515
  $tb->seekPrev();
479
516
  $this->assertEquals($tb->getFVint(FDI_ID), $i);
517
+ if ($i != $tb->getFVint(FDI_ID))
518
+ break;
480
519
  }
481
520
  $tb->seekPrev();
482
521
  $this->assertEquals($tb->getFVstr(FDI_NAME), 'kosaka');
483
522
  $db->endSnapshot();
523
+ // without snapshot
524
+ $vv = TEST_COUNT + 1;
525
+ $tb->clearBuffer();
526
+ $tb->setFV(FDI_ID, $vv);
527
+ $tb->seek();
528
+ $this->assertEquals($tb->getFVint(FDI_ID), $vv);
529
+ for ($i = TEST_COUNT; $i > 1; $i--)
530
+ {
531
+ $tb->seekPrev();
532
+ $this->assertEquals($tb->getFVint(FDI_ID), $i);
533
+ if ($i != $tb->getFVint(FDI_ID))
534
+ break;
535
+ }
536
+ $tb->seekPrev();
537
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'kosaka');
484
538
  }
485
539
  public function testGetGreater()
486
540
  {
@@ -627,53 +681,117 @@ class transactdTest extends PHPUnit_Framework_TestCase
627
681
  $tb->seek();
628
682
  $this->assertEquals($tb->getFVstr(FDI_NAME), 'ABC');
629
683
  }
630
- public function testSnapShot()
684
+ public function testSnapshot()
631
685
  {
632
686
  $db = new Bz\database();
633
- $db2 = new Bz\database();
634
- $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
635
- $this->assertEquals($db2->stat(), 0);
636
687
  $tb = $this->openTable($db);
637
688
  $this->assertNotEquals($tb, NULL);
689
+ $tbg = $db->openTable('group');
690
+ $this->assertEquals($db->stat(), 0);
691
+ $this->assertNotEquals($tbg, NULL);
692
+ $db2 = new Bz\database();
693
+ $this->assertEquals($db2->stat(), 0);
694
+ $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
638
695
  $tb2 = $this->openTable($db2);
639
696
  $this->assertNotEquals($tb2, NULL);
640
- $db->beginSnapshot();
697
+ $tbg2 = $db2->openTable('group');
698
+ $this->assertEquals($db2->stat(), 0);
699
+ $this->assertNotEquals($tbg2, NULL);
700
+
701
+ // No locking repeatable read
702
+ // ----------------------------------------------------
703
+ $db->beginSnapshot(); // CONSISTENT_READ is default
641
704
  $this->assertEquals($db->stat(), 0);
705
+ $db->beginTrn();
706
+ $this->assertEquals($db->stat(), Bz\transactd::STATUS_ALREADY_INSNAPSHOT);
707
+
642
708
  $tb->setKeyNum(0);
643
709
  $tb->seekFirst();
644
710
  $this->assertEquals($tb->stat(), 0);
645
711
  $firstValue = $tb->getFVstr(FDI_NAME);
646
712
  $tb->seekNext();
647
- // ----------------------------------------------------
648
- // Change data by another connection
713
+ $this->assertEquals($tb->stat(), 0);
714
+ $this->assertEquals($tb->getFVint(FDI_ID), 2);
715
+ $tbg->seekFirst();
716
+ $this->assertEquals($tbg->stat(), Bz\transactd::STATUS_EOF);
717
+ $this->assertEquals($tbg->recordCount(false), 0);
718
+
719
+ // Change data on 2 tables by another connection
649
720
  $tb2->setKeyNum(0);
650
721
  $tb2->seekFirst();
651
722
  $this->assertEquals($tb2->stat(), 0);
652
723
  $tb2->setFV(FDI_NAME, $tb2->getFVint(FDI_ID) + 1);
653
- $tb2->update();
654
- if (ISOLATION_READ_COMMITTED)
655
- $this->assertEquals($tb2->stat(), 0);
656
- elseif (ISOLATION_REPEATABLE_READ)
657
- $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
658
- // ----------------------------------------------------
724
+ $tb2->update(); //Change success
725
+ $this->assertEquals($tb2->stat(), 0);
726
+ $tbg2->setFV(FDI_ID, 1);
727
+ $tbg2->setFV(FDI_NAME, 'ABC');
728
+ $tbg2->insert();
729
+ $this->assertEquals($tbg2->stat(), 0);
730
+
731
+ // in-snapshot repeatable read check same value
659
732
  $tb->seekFirst();
660
733
  $secondValue = $tb->getFVstr(FDI_NAME);
661
734
  $this->assertEquals($tb->stat(), 0);
735
+ $this->assertEquals($secondValue, $firstValue, "$firstValue != $secondValue");
736
+
737
+ $tbg->seekFirst();
738
+ $this->assertEquals($tbg->stat(), Bz\transactd::STATUS_EOF);
739
+ $this->assertEquals($tbg->recordCount(false), 0);
740
+
741
+ // in-snapshot update
742
+ $tb->update();
743
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_INVALID_LOCKTYPE);
744
+
745
+ // in-snapshot insert
746
+ $tb->setFV(FDI_ID, 0);
747
+ $tb->insert();
748
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_INVALID_LOCKTYPE);
749
+
750
+ // phantom read
751
+ $tb2->setFV(FDI_ID, 29999);
752
+ $tb2->insert();
753
+ $this->assertEquals($tb2->stat(), 0);
754
+ $tb->setFV(FDI_ID, 29999);
755
+ $tb->seek();
756
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_NOT_FOUND_TI);
757
+
758
+ // clean up
759
+ $tb2->del();
760
+ $this->assertEquals($tb2->stat(), 0);
761
+
662
762
  $db->endSnapshot();
763
+ $this->assertEquals($db->stat(), 0);
764
+
765
+ // After snapshot, db can read new versions.
766
+ $tb->seekFirst();
663
767
  $this->assertEquals($tb->stat(), 0);
664
- if (ISOLATION_READ_COMMITTED)
665
- $this->assertNotEquals($secondValue, $firstValue);
666
- else
667
- $this->assertEquals($secondValue, $firstValue);
668
- // ----------------------------------------------------
768
+ $this->assertEquals($tb->getFVint(FDI_ID), 1);
769
+ $tbg->seekFirst();
770
+ $this->assertEquals($tbg->stat(), 0);
771
+ $this->assertEquals($tbg->recordCount(false), 1);
772
+
773
+ // gap lock
774
+ $db->beginSnapshot(Bz\transactd::MULTILOCK_GAP_SHARE);
775
+ $tb->seekLast(); // id = 30000
776
+ $this->assertEquals($tb->stat(), 0);
777
+ $tb->seekPrev(); // id = 20002
778
+ $this->assertEquals($tb->stat(), 0);
779
+ $tb->seekPrev(); // id = 20001
780
+ $this->assertEquals($tb->stat(), 0);
781
+
782
+ $tb2->setFV(FDI_ID, 29999);
783
+ $tb2->insert();
784
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
785
+
786
+ $db->endSnapshot();
669
787
  }
670
788
  public function testConflict()
671
789
  {
672
790
  $db = new Bz\database();
791
+ $tb = $this->openTable($db);
673
792
  $db2 = new Bz\database();
674
793
  $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
675
794
  $this->assertEquals($db2->stat(), 0);
676
- $tb = $this->openTable($db);
677
795
  $this->assertNotEquals($tb, NULL);
678
796
  $tb2 = $this->openTable($db2);
679
797
  $this->assertNotEquals($tb2, NULL);
@@ -717,93 +835,584 @@ class transactdTest extends PHPUnit_Framework_TestCase
717
835
  unset($db2);
718
836
  unset($db);
719
837
  }
720
- public function testTransactionLock()
838
+ // isoration Level ISO_REPEATABLE_READ
839
+ public function testTransactionLockRepeatable()
721
840
  {
722
841
  $db = new Bz\database();
842
+ $tb = $this->openTable($db);
843
+ $this->assertNotEquals($tb, NULL);
723
844
  $db2 = new Bz\database();
724
845
  $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
725
846
  $this->assertEquals($db2->stat(), 0);
726
- $tb = $this->openTable($db);
727
- $this->assertNotEquals($tb, NULL);
728
847
  $tb2 = $this->openTable($db2);
729
848
  $this->assertNotEquals($tb2, NULL);
730
- // ----------------------------------------------------
731
- // Read test that single record lock with read
732
- // ----------------------------------------------------
733
- $db->beginTrn(Bz\transactd::LOCK_SINGLE_NOWAIT);
734
- $tb->setKeyNum(0);
849
+
850
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
851
+ $this->assertEquals($db->stat(), 0);
852
+ // Test Invalid operation
853
+ $db->beginSnapshot();
854
+ $this->assertEquals($db->stat(), Bz\transactd::STATUS_ALREADY_INTRANSACTION);
855
+
856
+ // ------------------------------------------------------
857
+ // Test Read with lock
858
+ // ------------------------------------------------------
859
+ // lock(X) the first record
735
860
  $tb->seekFirst();
736
861
  $this->assertEquals($tb->stat(), 0);
737
- // unlock first record
862
+
863
+ // Add lock(X) the second record
738
864
  $tb->seekNext();
865
+
866
+ // No transaction user can read allways. Use consistent_read
739
867
  $tb2->seekFirst();
740
868
  $this->assertEquals($tb2->stat(), 0);
869
+
870
+ $tb2->seekNext();
871
+ $this->assertEquals($tb2->stat(), 0);
872
+
873
+ // The second transaction user can not lock same record.
741
874
  $db2->beginTrn();
742
875
  $tb2->setKeyNum(0);
876
+
877
+ // Try lock(X)
878
+ $tb2->seekFirst();
879
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
880
+ $db2->endTrn();
881
+ $db->endTrn();
882
+
883
+ // ------------------------------------------------------
884
+ // Test single record lock and Transaction lock
885
+ // ------------------------------------------------------
886
+ // lock(X) non-transaction
887
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
888
+
889
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
890
+ $this->assertEquals($db->stat(), 0);
891
+
892
+ // Try lock(X)
893
+ $tb->seekFirst();
894
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
895
+
896
+ // Remove lock(X)
897
+ $tb2->seekFirst();
898
+
899
+ // Retry lock(X)
900
+ $tb->seekFirst();
901
+ $this->assertEquals($tb->stat(), 0);
902
+
903
+ $tb->setFV(FDI_NAME, 'ABC');
904
+ $tb->update();
905
+ $this->assertEquals($tb->stat(), 0);
906
+
907
+ // No transaction user can read allways. Use consistent_read
743
908
  $tb2->seekFirst();
744
909
  $this->assertEquals($tb2->stat(), 0);
910
+ $this->assertNotEquals($tb2->getFVstr(FDI_NAME), 'ABC');
911
+
912
+ // ------------------------------------------------------
913
+ // Test Transaction lock and Transaction lock
914
+ // ------------------------------------------------------
915
+ $db2->beginTrn();
916
+ $this->assertEquals($db2->stat(), 0);
917
+
918
+ // try lock(X)
919
+ $tb2->seekFirst();
920
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
921
+
922
+ // Try unlock updated record. Can not unlock updated record.
923
+ $tb->unlock();
924
+
925
+ // try lock(X)
926
+ $tb2->seekFirst();
927
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
928
+
745
929
  $db2->endTrn();
746
930
  $db->endTrn();
931
+
747
932
  // ----------------------------------------------------
748
- // Can't read test that multi record lock with read
933
+ // Test phantom read
749
934
  // ----------------------------------------------------
750
- $db->beginTrn(Bz\transactd::LOCK_MULTI_NOWAIT);
751
- $tb->setKeyNum(0);
935
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
936
+ $this->assertEquals($db->stat(), 0);
937
+
938
+ // read last row
939
+ $tb->seekLast(); // lock(X) last id = 30000
940
+ $this->assertEquals($tb->stat(), 0);
941
+ $tb->seekPrev(); // Add lock(X)
942
+ $this->assertEquals($tb->stat(), 0);
943
+ $last2 = $tb->getFVint(FDI_ID);
944
+
945
+ // insert test row
946
+ $tb2->setFV(FDI_ID, 29999);
947
+ $tb2->insert(); // Can not insert by gap lock
948
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
949
+
950
+ $tb->seekLast();
951
+ $this->assertEquals($tb->stat(), 0);
952
+ $tb->seekPrev();
953
+ $this->assertEquals($tb->stat(), 0);
954
+ $this->assertEquals($tb->getFVint(FDI_ID), $last2);
955
+ $db->endTrn();
956
+
957
+ // ----------------------------------------------------
958
+ // Test Abort
959
+ // ----------------------------------------------------
960
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
961
+ $this->assertEquals($db->stat(), 0);
962
+
963
+ // lock(X)
752
964
  $tb->seekFirst();
753
965
  $this->assertEquals($tb->stat(), 0);
966
+ $tb->setFV(FDI_NAME, 'EFG');
967
+ $tb->update();
968
+ $this->assertEquals($tb->stat(), 0);
969
+
754
970
  // move from first record.
755
971
  $tb->seekNext();
756
- // not transactional user can not read
972
+ $db->abortTrn();
973
+
974
+ $tb2->setKeyNum(0);
975
+ $tb2->seekFirst();
976
+ $this->assertEquals($tb2->getFVstr(FDI_NAME), 'ABC');
977
+
978
+ // ----------------------------------------------------
979
+ // Test Query and locks Multi record lock
980
+ // ----------------------------------------------------
981
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
982
+ $this->assertEquals($db->stat(), 0);
983
+
984
+ // Test find records are lock.
985
+ $q = new Bz\query();
986
+ $q->where('id', '<=', 15)->and_('id', '<>', 13)->reject(0xFFFF);
987
+ $tb->setQuery($q);
988
+ $tb->setFV(FDI_ID, 12);
989
+ $tb->find();
990
+ while ($tb->stat() == 0)
991
+ $tb->findNext();
992
+ $this->assertEquals($tb->getFVint(FDI_ID), 15);
993
+
994
+ // all records locked
995
+ for ($i = 12; $i <= 16; $i++)
996
+ {
997
+ $tb2->setFV(FDI_ID, $i);
998
+ $tb2->seek(Bz\transactd::ROW_LOCK_X);
999
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1000
+ }
1001
+ $db->endTrn();
1002
+ }
1003
+ public function testTransactionLockReadCommited()
1004
+ {
1005
+ $db = new Bz\database();
1006
+ $tb = $this->openTable($db);
1007
+ $this->assertNotEquals($tb, NULL);
1008
+ $db2 = new Bz\database();
1009
+ $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
1010
+ $this->assertEquals($db2->stat(), 0);
1011
+ $tb2 = $this->openTable($db2);
1012
+ $this->assertNotEquals($tb2, NULL);
1013
+
1014
+ // ------------------------------------------------------
1015
+ // Test single record lock Transaction and read
1016
+ // ------------------------------------------------------
1017
+ $db->beginTrn(Bz\transactd::SINGLELOCK_READ_COMMITED);
1018
+ $this->assertEquals($db->stat(), 0);
1019
+ // Test Invalid operation
1020
+ $db->beginSnapshot();
1021
+ $this->assertEquals($db->stat(), Bz\transactd::STATUS_ALREADY_INTRANSACTION);
1022
+
1023
+ $tb->setKeyNum(0);
1024
+ $tb->seekFirst(); // lock(X)
1025
+ $this->assertEquals($tb->stat(), 0);
1026
+
1027
+ // Try lock(X)
1028
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1029
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1030
+
1031
+ // consistent read
1032
+ $tb2->seekFirst();
1033
+ $this->assertEquals($tb2->stat(), 0);
1034
+
1035
+ // Unlock first record. And lock(X) second record
1036
+ $tb->seekNext();
1037
+
1038
+ // test unlocked first record
757
1039
  $tb2->seekFirst();
1040
+ $this->assertEquals($tb2->stat(), 0);
1041
+ $tb2->update();
1042
+ $this->assertEquals($tb2->stat(), 0);
1043
+
1044
+ // The second record, consistent read
1045
+ $tb2->seekNext();
1046
+ $this->assertEquals($tb2->stat(), 0);
1047
+ // Try lock(X) whith lock(IX)
1048
+ $tb2->update();
758
1049
  $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
759
- // The second transactional user can not lock same record
1050
+
1051
+ // ------------------------------------------------------
1052
+ // Test single record lock Transaction and Transaction lock
1053
+ // ------------------------------------------------------
760
1054
  $db2->beginTrn();
761
- $tb2->setKeyNum(0);
1055
+ // Try lock(X)
762
1056
  $tb2->seekFirst();
1057
+ $this->assertEquals($tb2->stat(), 0);
1058
+ // Try lock(X)
1059
+ $tb2->seekNext();
763
1060
  $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
764
1061
  $db2->endTrn();
765
1062
  $db->endTrn();
766
- // ----------------------------------------------------
767
- // Can't read test that single record lock with change
768
- // ----------------------------------------------------
769
- $db->beginTrn(Bz\transactd::LOCK_SINGLE_NOWAIT);
770
- $tb->setKeyNum(0);
1063
+
1064
+ // ------------------------------------------------------
1065
+ // Test multi record lock Transaction and non-transaction read
1066
+ // ------------------------------------------------------
1067
+ $db->beginTrn(Bz\transactd::MULTILOCK_READ_COMMITED);
1068
+ $this->assertEquals($db->stat(), 0);
1069
+
1070
+ // lock(X) the first record
1071
+ $tb->seekFirst();
1072
+ $this->assertEquals($tb->stat(), 0);
1073
+
1074
+ // Add lock(X) the second record
1075
+ $tb->seekNext();
1076
+
1077
+ // No transaction user read can read allways. Use consistent_read
1078
+ $tb2->seekFirst();
1079
+ $this->assertEquals($tb2->stat(), 0);
1080
+
1081
+ $tb2->seekNext();
1082
+ $this->assertEquals($tb2->stat(), 0);
1083
+
1084
+ // ------------------------------------------------------
1085
+ // Test unlock
1086
+ // ------------------------------------------------------
1087
+ $tb2->seekFirst();
1088
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X);
1089
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1090
+
1091
+ $tb->unlock();
1092
+ // retry seekNext. Before operation is failed but do not lost currency.
1093
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X);
1094
+ $this->assertEquals($tb2->stat(), 0);
1095
+ $tb2->seekNext();
1096
+ // ------------------------------------------------------
1097
+ // Test undate record unlock
1098
+ // ------------------------------------------------------
1099
+ $tb->seekFirst();
1100
+ $this->assertEquals($tb->stat(), 0);
1101
+ $tb->seekNext();
1102
+ $this->assertEquals($tb->stat(), 0);
1103
+ $tb->update();
1104
+ $this->assertEquals($tb->stat(), 0);
1105
+ $tb->unlock(); // Can not unlock updated record
1106
+ $this->assertEquals($tb->stat(), 0);
1107
+ $tb2->seekFirst();
1108
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X);
1109
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1110
+
1111
+ // ------------------------------------------------------
1112
+ // Test multi record lock Transaction and Transaction
1113
+ // ------------------------------------------------------
1114
+ $db2->beginTrn();
1115
+ $this->assertEquals($db2->stat(), 0);
1116
+
1117
+ // Try lock(X)
1118
+ $tb2->seekFirst();
1119
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1120
+ $db2->endTrn();
1121
+ $db->endTrn();
1122
+
1123
+ // ------------------------------------------------------
1124
+ // Test multi record lock Transaction and non-transaction record lock
1125
+ // ------------------------------------------------------
1126
+ // lock(X) non-transaction
1127
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1128
+
1129
+ $db->beginTrn(Bz\transactd::SINGLELOCK_READ_COMMITED);
1130
+ $this->assertEquals($db->stat(), 0);
1131
+
1132
+ // Try lock(X)
1133
+ $tb->seekFirst();
1134
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1135
+
1136
+ // Remove lock(X)
1137
+ $tb2->seekFirst();
1138
+
1139
+ // Retry lock(X)
771
1140
  $tb->seekFirst();
772
1141
  $this->assertEquals($tb->stat(), 0);
1142
+
1143
+ // update in transaction
773
1144
  $tb->setFV(FDI_NAME, 'ABC');
774
1145
  $tb->update();
775
1146
  $this->assertEquals($tb->stat(), 0);
776
- // move from first record.
777
- $tb->seekNext();
778
- $tb2->seekFirst();
779
- $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1147
+
1148
+ // move from first record.
1149
+ $tb->seekNext();
1150
+
1151
+ // No transaction read can read allways. Use consistent_read
1152
+ $tb2->seekFirst();
1153
+ $this->assertEquals($tb2->stat(), 0);
1154
+ $tb2->update();
1155
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1156
+
1157
+ $db->endTrn();
1158
+ // ------------------------------------------------------
1159
+ // Test phantom read
1160
+ // ------------------------------------------------------
1161
+ $db->beginTrn(Bz\transactd::MULTILOCK_READ_COMMITED);
1162
+ $this->assertEquals($db->stat(), 0);
1163
+
1164
+ // read last row
1165
+ $tb->seekLast(); // lock(X) last id = 30000
1166
+ $this->assertEquals($tb->stat(), 0);
1167
+ $tb->seekPrev(); // Add lock(X)
1168
+ $this->assertEquals($tb->stat(), 0);
1169
+ $last2 = $tb->getFVint(FDI_ID);
1170
+
1171
+ //insert test row
1172
+ $tb2->setFV(FDI_ID, 29999);
1173
+ $tb2->insert();
1174
+ $this->assertEquals($tb2->stat(), 0);
1175
+
1176
+ $tb->seekLast();
1177
+ $this->assertEquals($tb->stat(), 0);
1178
+ $tb->seekPrev();
1179
+ $this->assertEquals($tb->stat(), 0);
1180
+ $this->assertNotEquals($tb->getFVint(FDI_ID), $last2);
1181
+ $db->endTrn();
1182
+
1183
+ // cleanup
1184
+ $tb2->del(); // last id = 29999
1185
+ $this->assertEquals($tb->stat(), 0);
1186
+
1187
+ // ------------------------------------------------------
1188
+ // Test use shared lock option
1189
+ // ------------------------------------------------------
1190
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
1191
+ $this->assertEquals($db->stat(), 0);
1192
+
1193
+ $db2->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
1194
+ $this->assertEquals($db2->stat(), 0);
1195
+
1196
+ $tb->seekLast(Bz\transactd::ROW_LOCK_S);
1197
+ $this->assertEquals($tb->stat(), 0);
1198
+ $tb2->seekLast(Bz\transactd::ROW_LOCK_S);
1199
+ $this->assertEquals($tb2->stat(), 0);
1200
+
1201
+ $tb->seekPrev(); // Lock(X)
1202
+ $this->assertEquals($tb->stat(), 0);
1203
+
1204
+ $tb2->seekPrev(Bz\transactd::ROW_LOCK_S);
1205
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1206
+
1207
+ $tb->seekPrev(Bz\transactd::ROW_LOCK_S);
1208
+ $this->assertEquals($tb->stat(), 0);
1209
+ $id = $tb->getFVint(FDI_ID);
1210
+
1211
+ $tb2->setFV(FDI_ID, $id);
1212
+ $tb2->seek(Bz\transactd::ROW_LOCK_S);
1213
+ $this->assertEquals($tb2->stat(), 0);
1214
+
1215
+ $db2->endTrn();
1216
+ $db->endTrn();
1217
+
1218
+ // ------------------------------------------------------
1219
+ // Abort test
1220
+ // ------------------------------------------------------
1221
+ $db->beginTrn(Bz\transactd::SINGLELOCK_READ_COMMITED);
1222
+ $this->assertEquals($db->stat(), 0);
1223
+
1224
+ $tb->seekFirst();
1225
+ $this->assertEquals($tb->stat(), 0);
1226
+ $tb->setFV(FDI_NAME, 'EFG');
1227
+ $tb->update();
1228
+ $this->assertEquals($tb->stat(), 0);
1229
+
1230
+ $tb->seekNext();
1231
+ $db->abortTrn();
1232
+ $tb2->setKeyNum(0);
1233
+ $tb2->seekFirst();
1234
+ $this->assertEquals($tb2->getFVstr(FDI_NAME), 'ABC');
1235
+
1236
+ // ------------------------------------------------------
1237
+ // Test Query and locks Single record lock
1238
+ // ------------------------------------------------------
1239
+ $db->beginTrn(Bz\transactd::SINGLELOCK_READ_COMMITED);
1240
+ $this->assertEquals($db->stat(), 0);
1241
+
1242
+ // Test find last record locked
1243
+ $q = new Bz\query();
1244
+ $q->where('id', '<=', '100');
1245
+ $tb->setQuery($q);
1246
+ $tb->setFV(FDI_ID, 1);
1247
+ $tb->find();
1248
+ while ($tb->stat() == 0)
1249
+ $tb->findNext();
1250
+ $this->assertEquals($tb->getFVint(FDI_ID), 100);
1251
+
1252
+ // find read last is record of id = 101.
1253
+ // Would be difficult to identify the last
1254
+ // access to records at SINGLELOCK_READ_COMMITED.
1255
+ // No match records are unlocked.
1256
+ $tb2->setFV(FDI_ID, 100);
1257
+ $tb2->seek(Bz\transactd::ROW_LOCK_X);
1258
+ $this->assertEquals($tb2->stat(), 0);
1259
+ $tb2->unlock();
1260
+ $db->endTrn();
1261
+
1262
+ // ------------------------------------------------------
1263
+ // Test Query and locks Multi record lock
1264
+ // ------------------------------------------------------
1265
+ $db->beginTrn(Bz\transactd::MULTILOCK_READ_COMMITED);
1266
+ $this->assertEquals($db->stat(), 0);
1267
+
1268
+ // Test find records are lock.
1269
+ $q->reset()->where('id', '<=', 15)->and_('id', '<>', 13)->reject(0xFFFF);
1270
+ $tb->setQuery($q);
1271
+ $tb->setFV(FDI_ID, 12);
1272
+ $tb->find();
1273
+ while ($tb->stat() == 0)
1274
+ $tb->findNext();
1275
+ $this->assertEquals($tb->getFVint(FDI_ID), 15);
1276
+
1277
+ for ($i = 12; $i <= 16; $i++)
1278
+ {
1279
+ $tb2->setFV(FDI_ID, $i);
1280
+ $tb2->seek(Bz\transactd::ROW_LOCK_X);
1281
+ if (($i == 16) || ($i == 13))
1282
+ $this->assertEquals($tb2->stat(), 0);
1283
+ else
1284
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1285
+ }
1286
+ $db->endTrn();
1287
+ }
1288
+ public function testRecordLock()
1289
+ {
1290
+ $db = new Bz\database();
1291
+ $tb = $this->openTable($db);
1292
+ $this->assertNotEquals($tb, NULL);
1293
+ $db2 = new Bz\database();
1294
+ $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
1295
+ $this->assertEquals($db2->stat(), 0);
1296
+ $tb2 = $this->openTable($db2);
1297
+ $this->assertNotEquals($tb2, NULL);
1298
+
1299
+ $tb->setKeyNum(0);
1300
+ $tb2->setKeyNum(0);
1301
+
1302
+ // Single record lock
1303
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X); // lock(X)
1304
+ $this->assertEquals($tb->stat(), 0);
1305
+ $tb2->seekFirst(); // Use consistent_read
1306
+ $this->assertEquals($tb2->stat(), 0);
1307
+
1308
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X); // Try lock(X) single
1309
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1310
+
1311
+ // try consistent_read. Check ended that before auto transaction
1312
+ $tb2->seekFirst();
1313
+ $this->assertEquals($tb2->stat(), 0);
1314
+
1315
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) second
1316
+ $this->assertEquals($tb2->stat(), 0);
1317
+
1318
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) third, second lock freed
1319
+ $this->assertEquals($tb2->stat(), 0);
1320
+
1321
+ $tb->seekNext(); // nobody lock second.
1322
+ $this->assertEquals($tb->stat(), 0);
1323
+ $tb->seekNext(Bz\transactd::ROW_LOCK_X); // Try lock(X) third
1324
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1325
+
1326
+ // Update test change third with lock(X)
1327
+ $tb2->setFV(FDI_NAME, 'The 3rd');
1328
+ $tb2->update(); // auto trn commit and unlock all locks
1329
+ $this->assertEquals($tb2->stat(), 0);
1330
+ $tb2->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) 4th
1331
+ $this->assertEquals($tb2->stat(), 0);
1332
+ $tb2->setFV(FDI_NAME, 'The 4th');
1333
+ $tb2->update(); // auto trn commit and unlock all locks
1334
+
1335
+ // Test unlock all locks, after update
1336
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X); // lock(X) first
1337
+ $this->assertEquals($tb2->stat(), 0);
1338
+ $tb->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) second
1339
+ $this->assertEquals($tb2->stat(), 0);
1340
+ $tb->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) third
1341
+ $this->assertEquals($tb2->stat(), 0);
1342
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'The 3rd');
1343
+
1344
+ // Test Insert, After record lock operation
1345
+ $tb->setFV(FDI_ID, 21000);
1346
+ $tb->insert();
1347
+ $this->assertEquals($tb->stat(), 0);
1348
+ $tb->del();
1349
+ $this->assertEquals($tb->stat(), 0);
1350
+
1351
+ // --------- Unlock test ----------------------------
1352
+ // 1 unlock()
1353
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1354
+ $this->assertEquals($tb->stat(), 0);
1355
+
1356
+ $tb->unlock();
1357
+
1358
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1359
+ $this->assertEquals($tb2->stat(), 0);
1360
+ $tb2->unlock();
1361
+
1362
+ // 2 auto tran ended
1363
+ $tb3 = $this->openTable($db2);
1364
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1365
+ $this->assertEquals($tb2->stat(), 0);
1366
+
1367
+ $tb3->seekLast(); //This operation is another table handle, then auto tran ended
1368
+ $this->assertEquals($tb3->stat(), 0);
1369
+
1370
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1371
+ $this->assertEquals($tb->stat(), 0);
1372
+ $tb->unlock();
1373
+
1374
+ // begin trn
1375
+ $tb3->seekFirst(Bz\transactd::ROW_LOCK_X);
1376
+ $this->assertEquals($tb3->stat(), 0);
1377
+
1378
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1379
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
780
1380
  $db2->beginTrn();
781
- $tb2->setKeyNum(0);
782
- $tb2->seekFirst();
783
- $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1381
+
1382
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1383
+ $this->assertEquals($tb->stat(), 0);
784
1384
  $db2->endTrn();
785
- $db->endTrn();
786
- // ----------------------------------------------------
787
- // Abort test that Single record lock transaction
788
- // ----------------------------------------------------
789
- $db->beginTrn(Bz\transactd::LOCK_SINGLE_NOWAIT);
790
- $tb->setKeyNum(0);
791
- $tb->seekFirst();
1385
+ $tb->unlock();
1386
+ // begin snapshot
1387
+ $tb3->seekFirst(Bz\transactd::ROW_LOCK_X);
1388
+ $this->assertEquals($tb3->stat(), 0);
1389
+
1390
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1391
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1392
+ $db2->beginSnapshot();
1393
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
792
1394
  $this->assertEquals($tb->stat(), 0);
793
- $tb->setFV(FDI_NAME, 'EFG');
794
- $tb->update();
1395
+ $db2->endSnapshot();
1396
+ $tb->unlock();
1397
+ // close Table
1398
+ $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
795
1399
  $this->assertEquals($tb->stat(), 0);
796
- // move from first record.
797
- $tb->seekNext();
798
- $db->abortTrn();
799
- $tb2->setKeyNum(0);
800
- $tb2->seekFirst();
801
- $this->assertEquals($tb2->getFVstr(FDI_NAME), 'ABC');
1400
+
1401
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1402
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1403
+ $tb->release();
1404
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1405
+ $this->assertEquals($tb2->stat(), 0);
1406
+ $tb2->unlock();
1407
+ // --------- End Unlock test ----------------------------
802
1408
  }
803
1409
  public function testExclusive()
804
1410
  {
805
1411
  // db mode exclusive
806
1412
  $db = new Bz\database();
1413
+ // ------------------------------------------------------
1414
+ // database WRITE EXCLUSIVE
1415
+ // ------------------------------------------------------
807
1416
  $db->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_EXCLUSIVE);
808
1417
  $this->assertEquals($db->stat(), 0);
809
1418
  $tb = $db->openTable(TABLENAME);
@@ -815,71 +1424,167 @@ class transactdTest extends PHPUnit_Framework_TestCase
815
1424
  $this->assertEquals($db2->stat(), 0);
816
1425
  $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF);
817
1426
  $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
818
-
819
- $tb2 = $db->openTable(TABLENAME);
820
- $this->assertEquals($db->stat(), 0);
821
-
822
- $tb->setKeyNum(0);
823
- $tb->seekFirst();
824
- $this->assertEquals($tb->stat(), 0);
825
-
826
- $tb->setFV(FDI_NAME, 'ABC123');
827
- $tb->update();
828
- $this->assertEquals($tb->stat(), 0);
829
-
830
- $tb2->setKeyNum(0);
831
- $tb2->seekFirst();
832
- $this->assertEquals($tb2->stat(), 0);
833
- $tb2->setFV(FDI_NAME, 'ABC124');
834
- $tb2->update();
835
- $this->assertEquals($tb2->stat(), 0);
836
-
837
1427
  $tb->close();
838
- $tb2->close();
839
1428
  $db->close();
840
1429
  $db2->close();
841
1430
 
1431
+ // ------------------------------------------------------
1432
+ // database WRITE EXCLUSIVE
1433
+ // ------------------------------------------------------
842
1434
  // table mode exclusive
843
1435
  $db = new Bz\database();
844
- $db->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_READONLY);
1436
+ $db->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
845
1437
  $this->assertEquals($db->stat(), 0);
846
- $tb = $db->openTable(TABLENAME, Bz\transactd::TD_OPEN_EXCLUSIVE);
1438
+ $tb = $db->openTable(TABLENAME, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
847
1439
  $this->assertEquals($db->stat(), 0);
848
1440
 
1441
+ // Read only open
849
1442
  $db2 = new Bz\database();
850
- $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
851
- $this->assertEquals($db2->stat(), 0);
852
1443
  $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF);
853
1444
  $this->assertEquals($db2->stat(), 0);
1445
+ $db2->close();
854
1446
 
855
- // Can not open table from other connections.
856
- $tb2 = $db2->openTable(TABLENAME);
857
- $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1447
+ // Normal open
1448
+ $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
1449
+ $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
1450
+ $this->assertEquals($db2->stat(), 0);
1451
+ $db2->close();
858
1452
 
859
- // Can open table from the same connection.
860
- $tb3 = $db->openTable(TABLENAME);
861
- $this->assertEquals($db->stat(), 0);
1453
+ // Write Exclusive open
1454
+ $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_EXCLUSIVE);
1455
+ $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1456
+ $db2->close();
862
1457
 
863
- $tb->close();
864
- if ($tb2 != NULL) { $tb2->close(); }
865
- $tb3->close();
866
- $db->close();
1458
+ // Read Exclusive open
1459
+ $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
1460
+ $this->assertEquals($db2->stat(), 0);
867
1461
  $db2->close();
1462
+ $db->close();
868
1463
 
869
- // reopen and update
870
- $db = new Bz\database();
871
- $db->open(URL);
1464
+ // ------------------------------------------------------
1465
+ // Normal and Exclusive open tables mix use
1466
+ // ------------------------------------------------------
1467
+ $db->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
872
1468
  $this->assertEquals($db->stat(), 0);
873
- $tb = $db->openTable(TABLENAME);
1469
+ $tb = $db->openTable(TABLENAME, Bz\transactd::TD_OPEN_NORMAL);
874
1470
  $this->assertEquals($db->stat(), 0);
1471
+ $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF);
1472
+ $this->assertEquals($db2->stat(), 0);
875
1473
 
876
- $tb->setKeyNum(0);
1474
+ $tb2 = $db->openTable('group', Bz\transactd::TD_OPEN_EXCLUSIVE);
1475
+ $this->assertEquals($db->stat(), 0);
1476
+ // Check tb2 Exclusive
1477
+ $tb3 = $db2->openTable('group', Bz\transactd::TD_OPEN_NORMAL);
1478
+ $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1479
+
1480
+ for ($i = 1; $i < 5; $i++)
1481
+ {
1482
+ $tb2->setFV(FDI_ID, $i + 1);
1483
+ $tb2->setFV(FDI_NAME, $i + 1);
1484
+ $tb2->insert();
1485
+ $this->assertEquals($tb2->stat(), 0);
1486
+ }
1487
+ $tb2->seekFirst();
1488
+ $this->assertEquals($tb2->stat(), 0);
1489
+ $tb->seekFirst();
1490
+ $this->assertEquals($tb->stat(), 0);
1491
+ $tb2->seekLast();
1492
+ $this->assertEquals($tb2->stat(), 0);
1493
+ $tb->seekLast();
1494
+ $this->assertEquals($tb->stat(), 0);
1495
+ // Normal close first
1496
+ $tb->close();
1497
+ $tb2->seekLast();
1498
+ $this->assertEquals($tb2->stat(), 0);
1499
+ $tb2->seekFirst();
1500
+ $this->assertEquals($tb2->stat(), 0);
1501
+
1502
+ // Reopen Normal
1503
+ $tb = $db->openTable('user');
1504
+ $tb2->seekFirst();
1505
+ $this->assertEquals($tb2->stat(), 0);
1506
+ $tb->seekFirst();
1507
+ $this->assertEquals($tb->stat(), 0);
1508
+ $tb2->seekLast();
1509
+ $this->assertEquals($tb2->stat(), 0);
1510
+ $tb->seekLast();
1511
+ $this->assertEquals($tb->stat(), 0);
1512
+ // Exclusive close first
1513
+ $tb2->close();
1514
+ $tb->seekFirst();
1515
+ $this->assertEquals($tb->stat(), 0);
1516
+ $tb->seekLast();
1517
+ $this->assertEquals($tb->stat(), 0);
1518
+
1519
+ // ------------------------------------------------------
1520
+ // Normal and Exclusive opend tables mix transaction
1521
+ // ------------------------------------------------------
1522
+ $tb2 = $db->openTable('group', Bz\transactd::TD_OPEN_EXCLUSIVE);
1523
+ $this->assertEquals($tb2->stat(), 0);
1524
+ // Check tb2 Exclusive
1525
+ $tb3 = $db2->openTable('group', Bz\transactd::TD_OPEN_NORMAL);
1526
+ $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1527
+
1528
+ $db->beginTrn();
877
1529
  $tb->seekFirst();
878
1530
  $this->assertEquals($tb->stat(), 0);
1531
+ $tb->setFV(FDI_NAME, 'mix trn');
1532
+ $tb->update();
1533
+ $this->assertEquals($tb->stat(), 0);
1534
+
1535
+ $tb2->seekFirst();
1536
+ $this->assertEquals($tb2->stat(), 0);
1537
+ $tb2->setFV(FDI_NAME, 'first mix trn tb2');
1538
+ $tb2->update();
1539
+ $this->assertEquals($tb2->stat(), 0);
1540
+
1541
+ $tb2->seekNext();
1542
+ $tb2->setFV(FDI_NAME, 'second mix trn tb2');
1543
+ $tb2->update();
1544
+ $this->assertEquals($tb2->stat(), 0);
1545
+ $db->endTrn();
1546
+ $tb2->seekFirst();
1547
+ $v = $tb2->getFVstr(FDI_NAME);
1548
+ $this->assertEquals($v, 'first mix trn tb2');
1549
+ $tb2->seekNext();
1550
+ $v = $tb2->getFVstr(FDI_NAME);
1551
+ $this->assertEquals($v, 'second mix trn tb2');
1552
+
1553
+ $tb2->close();
1554
+ $tb->close();
1555
+ }
1556
+ public function testMultiDatabase()
1557
+ {
1558
+ $db = new Bz\database();
1559
+ $tb = $this->openTable($db);
1560
+ $this->assertNotEquals($tb, NULL);
1561
+ $db2 = new Bz\database();
1562
+ $this->openDatabase($db2);
1563
+ $tb2 = $db2->openTable('group');
1564
+ $this->assertEquals($db2->stat(), 0);
1565
+ $this->assertNotEquals($tb2, NULL);
1566
+
1567
+ $db->beginTrn();
1568
+ $db2->beginTrn();
879
1569
 
880
- $tb->setFV(FDI_NAME, 'ABC123');
1570
+ $tb->seekFirst();
1571
+ $this->assertEquals($tb->stat(), 0);
1572
+ $v = $tb->getFVstr(FDI_NAME);
1573
+ $tb->setFV(FDI_NAME, 'MultiDatabase');
881
1574
  $tb->update();
1575
+
1576
+ $tb2->seekFirst();
1577
+ $this->assertEquals($tb2->stat(), 0);
1578
+ $tb2->setFV(FDI_NAME, 'MultiDatabase');
1579
+ $tb2->update();
1580
+ $this->assertEquals($tb2->stat(), 0);
1581
+ $db2->endTrn();
1582
+ $db->abortTrn();
1583
+
1584
+ $tb->seekFirst();
882
1585
  $this->assertEquals($tb->stat(), 0);
1586
+ $v2 = $tb->getFVstr(FDI_NAME);
1587
+ $this->assertEquals($v, $v2);
883
1588
  }
884
1589
  public function testInsert2()
885
1590
  {
@@ -976,8 +1681,9 @@ class transactdTest extends PHPUnit_Framework_TestCase
976
1681
  {
977
1682
  // second connection
978
1683
  $db2 = new Bz\database();
979
- $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
980
- $this->assertEquals($db->stat(), 0);
1684
+ $db2->connect(PROTOCOL . HOSTNAME, true);
1685
+ $this->assertEquals($db2->stat(), 0);
1686
+ unset($db2);
981
1687
  $db->disconnect(PROTOCOL . HOSTNAME);
982
1688
  $this->assertEquals($db->stat(), 0);
983
1689
  }
@@ -1188,103 +1894,103 @@ class transactdTest extends PHPUnit_Framework_TestCase
1188
1894
  //}
1189
1895
  // Set Ansi Get Wide
1190
1896
  // too long string
1191
- $tb->setFVA(FDI_NAME, '1234567');
1897
+ $tb->setFV(FDI_NAME, '1234567');
1192
1898
  if ($varCharField)
1193
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '123');
1899
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '123');
1194
1900
  else
1195
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '123456');
1901
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '123456');
1196
1902
  //if ($this->isWindows())
1197
1903
  // $this->assertEquals($tb->getFVWstr(FDI_GROUP), '68');
1198
1904
  //else
1199
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1905
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1200
1906
  // short string
1201
- $tb->setFVA(FDI_NAME, '13 ');
1202
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '13 ');
1907
+ $tb->setFV(FDI_NAME, '13 ');
1908
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '13 ');
1203
1909
  //if ($this->isWindows())
1204
1910
  // $this->assertEquals($tb->getFVWstr(FDI_GROUP), '68');
1205
1911
  //else
1206
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1912
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1207
1913
  // too long kanji
1208
1914
  if ($unicodeField)
1209
1915
  {
1210
1916
  if ($this->isWindows())
1211
1917
  {
1212
- $tb->setFVA(FDI_NAME, 'あいうえお𩸽'); // hiragana 'aiueo' kanji 'hokke'
1918
+ $tb->setFV(FDI_NAME, 'あいうえお𩸽'); // hiragana 'aiueo' kanji 'hokke'
1213
1919
  if ($varCharField)
1214
- $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいう');
1920
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいう');
1215
1921
  else
1216
- $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいうえお');
1922
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいうえお');
1217
1923
  }
1218
1924
  }
1219
1925
  else
1220
1926
  {
1221
- $tb->setFVA(FDI_NAME, '0松本市'); // numeric '0' kanji 'matumostoshi'
1222
- $is_valid_value = ($tb->getFVAstr(FDI_NAME) == '0松本');
1927
+ $tb->setFV(FDI_NAME, '0松本市'); // numeric '0' kanji 'matumostoshi'
1928
+ $is_valid_value = ($tb->getFVstr(FDI_NAME) == '0松本');
1223
1929
  $this->assertTrue($is_valid_value);
1224
1930
  if (! $is_valid_value)
1225
- print_r($tb->getFVAstr(FDI_NAME));
1931
+ print_r($tb->getFVstr(FDI_NAME));
1226
1932
  }
1227
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1933
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1228
1934
  //// Set Wide Get Ansi
1229
1935
  //if ($this->isWindows())
1230
1936
  //{
1231
1937
  // // too long string
1232
1938
  // $tb->setFVW(FDI_NAME, '1234567');
1233
1939
  // if ($varCharField)
1234
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), '123');
1940
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), '123');
1235
1941
  // else
1236
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), '123456');
1942
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), '123456');
1237
1943
  // $this->assertEquals($tb->getFVWstr(FDI_GROUP), '68');
1238
1944
  // // short string
1239
1945
  // $tb->setFVW(1, '23 ');
1240
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), '23 ');
1946
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), '23 ');
1241
1947
  // $this->assertEquals($tb->getFVWstr(FDI_GROUP), '68');
1242
1948
  // // too long kanji
1243
1949
  // if ($unicodeField)
1244
1950
  // {
1245
1951
  // $tb->setFVW(FDI_NAME, 'あいうえお𩸽'); // hiragana 'aiueo' kanji 'hokke'
1246
1952
  // if ($varCharField)
1247
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいう');
1953
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいう');
1248
1954
  // else
1249
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいうえお');
1955
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいうえお');
1250
1956
  // }
1251
1957
  // else
1252
1958
  // {
1253
1959
  // $tb->setFVW(FDI_NAME, '0松本市'); // numeric '0' kanji 'matumostoshi'
1254
- // $this->assertEquals($tb->getFVAstr(FDI_NAME), '0松本');
1960
+ // $this->assertEquals($tb->getFVstr(FDI_NAME), '0松本');
1255
1961
  // }
1256
1962
  // $this->assertEquals($tb->getFVWstr(FDI_GROUP), '68');
1257
1963
  //}
1258
1964
  // Set Ansi Get Ansi
1259
1965
  // too long string
1260
- $tb->setFVA(FDI_NAME, '1234567');
1966
+ $tb->setFV(FDI_NAME, '1234567');
1261
1967
  if ($varCharField)
1262
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '123');
1968
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '123');
1263
1969
  else
1264
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '123456');
1265
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1970
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '123456');
1971
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1266
1972
  // short string
1267
- $tb->setFVA(FDI_NAME, '13 ');
1268
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '13 ');
1269
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1973
+ $tb->setFV(FDI_NAME, '13 ');
1974
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '13 ');
1975
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1270
1976
  // too long lanji
1271
1977
  if ($unicodeField)
1272
1978
  {
1273
1979
  if ($this->isWindows())
1274
1980
  {
1275
- $tb->setFVA(FDI_NAME, 'あいうえお𩸽'); // hiragana 'aiueo' kanji 'hokke'
1981
+ $tb->setFV(FDI_NAME, 'あいうえお𩸽'); // hiragana 'aiueo' kanji 'hokke'
1276
1982
  if ($varCharField)
1277
- $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいう');
1983
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいう');
1278
1984
  else
1279
- $this->assertEquals($tb->getFVAstr(FDI_NAME), 'あいうえお');
1985
+ $this->assertEquals($tb->getFVstr(FDI_NAME), 'あいうえお');
1280
1986
  }
1281
1987
  }
1282
1988
  else
1283
1989
  {
1284
- $tb->setFVA(FDI_NAME, '0松本市'); // numeric '0' kanji 'matumostoshi'
1285
- $this->assertEquals($tb->getFVAstr(FDI_NAME), '0松本');
1990
+ $tb->setFV(FDI_NAME, '0松本市'); // numeric '0' kanji 'matumostoshi'
1991
+ $this->assertEquals($tb->getFVstr(FDI_NAME), '0松本');
1286
1992
  }
1287
- $this->assertEquals($tb->getFVAstr(FDI_GROUP), '68');
1993
+ $this->assertEquals($tb->getFVstr(FDI_GROUP), '68');
1288
1994
  }
1289
1995
  public function testVarField()
1290
1996
  {
@@ -1318,7 +2024,6 @@ class transactdTest extends PHPUnit_Framework_TestCase
1318
2024
  $this->assertEquals($db->stat(), 0);
1319
2025
  // utf8 varchar
1320
2026
  $this->setGetVar($tb, true, true);
1321
- $tb->close();
1322
2027
  }
1323
2028
  private function doVarInsert($db, $name, $codePage, $str, $startid, $endid, $bulk)
1324
2029
  {
@@ -1934,7 +2639,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
1934
2639
  $td->id = $id;
1935
2640
  $td->pageSize = 2048;
1936
2641
  $td->schemaCodePage = Bz\transactd::CP_UTF8;
1937
- $td->charsetIndex = Bz\transactd::CHARSET_UTF8B4;
2642
+ $td->charsetIndex = Bz\transactd::CHARSET_UTF8;
1938
2643
  $dbdef->insertTable($td);
1939
2644
  $this->assertEquals($dbdef->stat(), 0);
1940
2645
  // id field
@@ -1990,7 +2695,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
1990
2695
  $td->id = $id;
1991
2696
  $td->pageSize = 2048;
1992
2697
  $td->schemaCodePage = Bz\transactd::CP_UTF8;
1993
- $td->charsetIndex = Bz\transactd::CHARSET_UTF8B4;
2698
+ $td->charsetIndex = Bz\transactd::CHARSET_UTF8;
1994
2699
  $dbdef->insertTable($td);
1995
2700
  $this->assertEquals($dbdef->stat(), 0);
1996
2701
  // code field
@@ -2029,7 +2734,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
2029
2734
  $td->id = $id;
2030
2735
  $td->pageSize = 2048;
2031
2736
  $td->schemaCodePage = Bz\transactd::CP_UTF8;
2032
- $td->charsetIndex = Bz\transactd::CHARSET_UTF8B4;
2737
+ $td->charsetIndex = Bz\transactd::CHARSET_UTF8;
2033
2738
  $dbdef->insertTable($td);
2034
2739
  $this->assertEquals($dbdef->stat(), 0);
2035
2740
  // id field
@@ -2042,6 +2747,11 @@ class transactdTest extends PHPUnit_Framework_TestCase
2042
2747
  $fd->setName('comment');
2043
2748
  $fd->type = Bz\transactd::ft_myvarchar;
2044
2749
  $fd->setLenByCharnum(60);
2750
+ // blob field
2751
+ $fd = $dbdef->insertField($id, 2);
2752
+ $fd->setName('blob');
2753
+ $fd->type = Bz\transactd::ft_myblob;
2754
+ $fd->len = 10;
2045
2755
  // key 0 (primary) id
2046
2756
  $kd = $dbdef->insertKey($id, 0);
2047
2757
  $kd->segment(0)->fieldNum = 0;
@@ -2094,10 +2804,10 @@ class transactdTest extends PHPUnit_Framework_TestCase
2094
2804
  {
2095
2805
  $tb->setFV(0, $i);
2096
2806
  $tb->setFV(1, "$i comment");
2807
+ $tb->setFV(2, "$i blob");
2097
2808
  $tb->insert();
2098
2809
  $this->assertEquals($tb->stat(), 0);
2099
2810
  }
2100
- $tb->close();
2101
2811
  $db->endTrn();
2102
2812
  }
2103
2813
 
@@ -2106,10 +2816,21 @@ class transactdTest extends PHPUnit_Framework_TestCase
2106
2816
  $db = new Bz\database();
2107
2817
  // check database existence
2108
2818
  $db->open(URL_QT, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
2109
- if ($db->stat() === 0) {
2110
- return;
2819
+ if ($db->stat() !== 0)
2820
+ echo("\nDatabase " . DBNAME_QT . " not found");
2821
+ else
2822
+ {
2823
+ $def = $db->dbDef();
2824
+ $td = $def->tableDefs(3);
2825
+ if ($td != NULL && $td->fieldCount === 3) {
2826
+ $tb = $db->openTable('extention');
2827
+ if ($db->stat() === 0 && $tb->recordCount(false) === TEST_COUNT)
2828
+ return;
2829
+ $tb->close();
2830
+ }
2831
+ $db->drop();
2111
2832
  }
2112
- echo("\nDatabase " . DBNAME_QT . " not found\n");
2833
+ echo("\nCreate database " . DBNAME_QT . "\n");
2113
2834
  $db->create(URL_QT);
2114
2835
  $this->assertEquals($db->stat(), 0);
2115
2836
  $db->open(URL_QT, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_NORMAL);
@@ -2276,15 +2997,22 @@ class transactdTest extends PHPUnit_Framework_TestCase
2276
2997
  $q->select('id', 'name', 'group')->where('id', '<=', 15000);
2277
2998
  $rs = $atu->index(0)->keyValue(1)->read($q);
2278
2999
  $this->assertEquals($rs->size(), 15000);
3000
+ $this->assertEquals($rs->fieldDefs()->size(), 3);
2279
3001
 
2280
3002
  // Join extention::comment
2281
3003
  $q->reset();
2282
- $ate->index(0)->join($rs,
2283
- $q->select('comment')->optimize(Bz\queryBase::joinHasOneOrHasMany), 'id');
3004
+ $this->assertEquals($q->selectCount(), 0);
3005
+
3006
+ $q->select('comment')->optimize(Bz\queryBase::joinHasOneOrHasMany);
3007
+ $this->assertEquals($q->selectCount(), 1);
3008
+ $ate->index(0)->join($rs, $q, 'id');
3009
+ $this->assertEquals($q->selectCount(), 1);
2284
3010
  $this->assertEquals($rs->size(), 15000);
3011
+ $this->assertEquals($rs->fieldDefs()->size(), 4);
2285
3012
 
2286
3013
  // reverse and get first (so it means 'get last')
2287
3014
  $last = $rs->reverse()->first();
3015
+ $this->assertEquals($rs->size(), 15000);
2288
3016
  $this->assertEquals($last['id'], 15000);
2289
3017
  $this->assertEquals($last['comment'], '15000 comment');
2290
3018
 
@@ -2350,9 +3078,13 @@ class transactdTest extends PHPUnit_Framework_TestCase
2350
3078
 
2351
3079
  // clone
2352
3080
  $rsv = clone $rs;
3081
+ $this->assertEquals($rsv->size(), 16000);
2353
3082
  $gq->reset();
2354
3083
  $count3 = new Bz\count('count3');
2355
3084
  $gq->addFunction($count3)->keyField('group');
3085
+ $this->assertEquals($gq->functionCount(), 1);
3086
+ $this->assertEquals($gq->getKeyFields()->count(), 1);
3087
+
2356
3088
  $rs->groupBy($gq);
2357
3089
  $this->assertEquals($rs->size(), 5);
2358
3090
  $this->assertEquals($rsv->size(), 16000);
@@ -2387,6 +3119,238 @@ class transactdTest extends PHPUnit_Framework_TestCase
2387
3119
  $q3->keyField('group', 'id');
2388
3120
  unset($q3);
2389
3121
  }
3122
+ public function testPrepareJoin()
3123
+ {
3124
+ $db = new Bz\database();
3125
+ $db->open(URL_QT);
3126
+ $this->assertEquals($db->stat(), 0);
3127
+
3128
+ $atu = new Bz\ActiveTable($db, 'user');
3129
+ $atu->alias('名前', 'name');
3130
+ $atg = new Bz\ActiveTable($db, 'groups');
3131
+ $atg->alias('name', 'group_name');
3132
+ $ate = new Bz\ActiveTable($db, 'extention');
3133
+ $q = new Bz\query();
3134
+
3135
+ $q->select('id', 'name', 'group')->where('id', '<=', '?');
3136
+ $pq = $atu->prepare($q);
3137
+
3138
+ // int value
3139
+ $rs = $atu->index(0)->keyValue(1)->read($pq, 15000);
3140
+ $this->assertEquals($rs->size(), 15000);
3141
+ $this->assertEquals($rs->fieldDefs()->size(), 3);
3142
+ // string value
3143
+ $rs = $atu->index(0)->keyValue(1)->read($pq, '15000');
3144
+ $this->assertEquals($rs->size(), 15000);
3145
+ $this->assertEquals($rs->fieldDefs()->size(), 3);
3146
+ // double value
3147
+ $rs = $atu->index(0)->keyValue(1)->read($pq, 15000.000);
3148
+ $this->assertEquals($rs->size(), 15000);
3149
+ $this->assertEquals($rs->fieldDefs()->size(), 3);
3150
+ // Using supply value
3151
+ $pq->supplyValue(0, 15000);
3152
+ $rs = $atu->index(0)->keyValue(1)->read($pq);
3153
+ $this->assertEquals($rs->size(), 15000);
3154
+ $this->assertEquals($rs->fieldDefs()->size(), 3);
3155
+
3156
+ // Join extention::comment
3157
+ $q->reset();
3158
+ $this->assertEquals($q->selectCount(), 0);
3159
+ $q->select('comment')->optimize(Bz\queryBase::joinHasOneOrHasMany);
3160
+ $this->assertEquals($q->selectCount(), 1);
3161
+ $pq = $ate->prepare($q);
3162
+
3163
+ $ate->index(0)->join($rs, $pq, 'id');
3164
+ $this->assertEquals($q->selectCount(), 1);
3165
+ $this->assertEquals($rs->size(), 15000);
3166
+ $this->assertEquals($rs->fieldDefs()->size(), 4);
3167
+ // reverse and get first (so it means 'get last')
3168
+ $last = $rs->reverse()->first();
3169
+ $this->assertEquals($rs->size(), 15000);
3170
+ $this->assertEquals($last['id'], 15000);
3171
+ $this->assertEquals($last['comment'], '15000 comment');
3172
+
3173
+ // Join group::name
3174
+ $q->reset()->select('group_name');
3175
+ $pq = $atg->prepare($q);
3176
+ $atg->index(0)->join($rs, $pq, 'group');
3177
+ $this->assertEquals($rs->size(), 15000);
3178
+
3179
+ // get last (the rs is reversed, so it means 'get first')
3180
+ $first = $rs->last();
3181
+ $this->assertEquals($first['id'], 1);
3182
+ $this->assertEquals($first['comment'], '1 comment');
3183
+ $this->assertEquals($first['group_name'], '1 group');
3184
+
3185
+ // row in rs[15000 - 9]
3186
+ $rec = $rs[15000 - 9];
3187
+ $this->assertEquals($rec['group_name'], '4 group');
3188
+ }
3189
+ public function testServerPrepareJoin()
3190
+ {
3191
+ define('NO_RECORD_ID', 5);
3192
+ $db = new Bz\database();
3193
+ $db->open(URL_QT);
3194
+ $this->assertEquals($db->stat(), 0);
3195
+
3196
+ $atu = new Bz\ActiveTable($db, 'user');
3197
+ $atu->alias('名前', 'name');
3198
+ $atg = new Bz\ActiveTable($db, 'groups');
3199
+ $atg->alias('name', 'group_name');
3200
+ $ate = new Bz\ActiveTable($db, 'extention');
3201
+ $q = new Bz\query();
3202
+
3203
+ $q->select('id', 'name', 'group')->where('id', '<=', '?');
3204
+ $stmt1 = $atu->prepare($q, true);
3205
+ $this->assertNotEquals($stmt1, NULL);
3206
+
3207
+ $q->reset()->select('comment')->optimize(Bz\queryBase::joinHasOneOrHasMany);
3208
+ $stmt2 = $ate->prepare($q, true);
3209
+ $this->assertNotEquals($stmt2, NULL);
3210
+
3211
+ $q->reset()->select('group_name');
3212
+ $stmt3 = $atg->prepare($q, true);
3213
+ $this->assertNotEquals($stmt3, NULL);
3214
+
3215
+ $rs = $atu->index(0)->keyValue(1)->read($stmt1, 15000);
3216
+ $this->assertEquals($rs->size(), 15000);
3217
+
3218
+ // Join extention::comment
3219
+ $ate->index(0)->join($rs, $stmt2, 'id');
3220
+ $this->assertEquals($rs->size(), 15000);
3221
+
3222
+ // test reverse
3223
+ $last = $rs->reverse()->first();
3224
+ $this->assertEquals($last['id'], 15000);
3225
+ $this->assertEquals($last['comment'], '15000 comment');
3226
+
3227
+ // Join group::name
3228
+ $atg->index(0)->join($rs, $stmt3, 'group');
3229
+ $this->assertEquals($rs->size(), 15000);
3230
+ $first = $rs->last();
3231
+
3232
+ $this->assertEquals($first['id'], 1);
3233
+ $this->assertEquals($first['comment'], '1 comment');
3234
+ $this->assertEquals($first['group_name'], '1 group');
3235
+
3236
+ // $rs[15000 - 9];
3237
+ $rec = $rs[15000 - 9];
3238
+ $this->assertEquals($rec['group_name'], '4 group');
3239
+
3240
+ // Test orderby
3241
+ $rs->orderBy('group_name');
3242
+ // $rs[0];
3243
+ $this->assertEquals($rs[0]['group_name'], '1 group');
3244
+
3245
+ /*
3246
+ sortFields orderRv;
3247
+ orderRv.add('group_name', false);
3248
+ rs.orderBy(orderRv);
3249
+
3250
+ sortFields order;
3251
+ order.add('group_name', true);
3252
+ rs.orderBy(order);
3253
+ BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0]['group_name'].c_str()) ==
3254
+ _tstring('1 group'),
3255
+ "group_name = 1 group "
3256
+ << string(rs[(size_t)0]['group_name'].a_str()));
3257
+ */
3258
+ // All fields
3259
+ $rs->clear();
3260
+ $q->reset()->all();
3261
+ $q->where('id', '<=', '?');
3262
+ $stmt1 = $atu->prepare($q, true);
3263
+ $rs = $atu->keyValue(1)->read($stmt1, 15000);
3264
+ $this->assertEquals($rs->size(), 15000);
3265
+ if ($rs->size() == 15000)
3266
+ {
3267
+ for ($i = 0; $i < 15000; $i++)
3268
+ $this->assertEquals($rs[$i]['id'], $i + 1);
3269
+ }
3270
+
3271
+ $ate->join($rs, $stmt2, 'id');
3272
+ $this->assertEquals($rs->size(), 15000);
3273
+ $atg->join($rs, $stmt3, 'group');
3274
+ $this->assertEquals($rs->size(), 15000);
3275
+
3276
+ // OuterJoin
3277
+ $tb = $ate->table();
3278
+ $tb->setFV('id', NO_RECORD_ID);
3279
+ $tb->seek();
3280
+ $this->assertEquals($tb->stat(), 0);
3281
+ if ($tb->stat() == 0)
3282
+ $tb->del();
3283
+ $this->assertEquals($tb->stat(), 0);
3284
+ $q->reset()->select('comment', 'blob')->optimize(Bz\queryBase::joinHasOneOrHasMany);
3285
+ $stmt2 = $ate->prepare($q, true);
3286
+
3287
+ // Join is remove record(s) no join target record.
3288
+ $rs->clear();
3289
+ $rs = $atu->keyValue(1)->read($stmt1, 15000);
3290
+ $ate->join($rs, $stmt2, 'id');
3291
+ $this->assertEquals($rs->size(), 14999);
3292
+ $this->assertEquals($rs[NO_RECORD_ID - 1]['id'], NO_RECORD_ID + 1);
3293
+ $this->assertEquals($rs[NO_RECORD_ID - 1]['comment'], '' . (NO_RECORD_ID + 1) . ' comment');
3294
+ $this->assertEquals($rs[NO_RECORD_ID - 1]['blob'], '' . (NO_RECORD_ID + 1) . ' blob');
3295
+
3296
+ // OuterJoin is no remove record(s) no join target record.
3297
+ $rs->clear();
3298
+ $rs = $atu->keyValue(1)->read($stmt1, 15000);
3299
+ $ate->outerJoin($rs, $stmt2, 'id');
3300
+ $this->assertEquals($rs->size(), 15000);
3301
+ $atg->outerJoin($rs, $stmt3, 'group');
3302
+ $this->assertEquals($rs->size(), 15000);
3303
+
3304
+ $this->assertEquals($rs[NO_RECORD_ID - 1]->isInvalidRecord(), true);
3305
+ $this->assertEquals($rs[NO_RECORD_ID]['comment'], '' . (NO_RECORD_ID + 1) . ' comment');
3306
+ $this->assertEquals($rs[NO_RECORD_ID]['blob'], '' . (NO_RECORD_ID + 1) . ' blob');
3307
+
3308
+ // OuterJoin All Join fields
3309
+ $q->reset()->optimize(Bz\queryBase::joinHasOneOrHasMany)->all();
3310
+ $stmt2 = $ate->prepare($q, true);
3311
+ $rs->clear();
3312
+ $rs = $atu->keyValue(1)->read($stmt1, 15000);
3313
+ $ate->outerJoin($rs, $stmt2, 'id');
3314
+ $this->assertEquals($rs->size(), 15000);
3315
+ $this->assertEquals($rs[NO_RECORD_ID - 1]->isInvalidRecord(), true);
3316
+ $this->assertEquals($rs[NO_RECORD_ID]['comment'], '' . (NO_RECORD_ID + 1) . ' comment');
3317
+ $this->assertEquals($rs[NO_RECORD_ID]['blob'], '' . (NO_RECORD_ID + 1) . ' blob');
3318
+
3319
+ // Test clone blob field
3320
+ $rs2 = clone($rs);
3321
+ $this->assertEquals($rs2->size(), 15000);
3322
+ $this->assertEquals($rs2[NO_RECORD_ID - 1]->isInvalidRecord(), true);
3323
+ $this->assertEquals($rs2[NO_RECORD_ID]['comment'], '' . (NO_RECORD_ID + 1) . ' comment');
3324
+ $this->assertEquals($rs2[NO_RECORD_ID]['blob'], '' . (NO_RECORD_ID + 1) . ' blob');
3325
+
3326
+ // hasManyJoin inner
3327
+ $rs->clear();
3328
+ $q->reset()->reject(0xFFFF)->limit(0)->all();
3329
+ $rs = $atg->keyValue(1)->read($q);
3330
+ $this->assertEquals($rs->size(), 100);
3331
+ $q->all()->optimize(Bz\queryBase::joinHasOneOrHasMany);
3332
+ $atu->index(1)->join($rs, $q, 'code');
3333
+ $this->assertEquals($rs->size(), 20000);
3334
+
3335
+ // hasManyJoin outer
3336
+ $rs->clear();
3337
+ $q->reset()->reject(0xFFFF)->limit(0)->all();
3338
+ $rs = $atg->keyValue(1)->read($q);
3339
+ $this->assertEquals($rs->size(), 100);
3340
+ $q->all()->optimize(Bz\queryBase::joinHasOneOrHasMany);
3341
+ $atu->index(1)->outerJoin($rs, $q, 'code');
3342
+ $this->assertEquals($rs->size(), 20095);
3343
+
3344
+ // restore record
3345
+ $tb->clearBuffer();
3346
+ $tb->setFV('id', NO_RECORD_ID);
3347
+ $tb->setFV('comment', '5 comment');
3348
+ $tb->setFV('blob', '5 blob');
3349
+ $tb->insert();
3350
+ $this->assertEquals($tb->stat(), 0);
3351
+ if ($tb->stat() != 0)
3352
+ $db->drop();
3353
+ }
2390
3354
  public function testWritableRecord()
2391
3355
  {
2392
3356
  $db = new Bz\database();