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
@@ -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();