1
2 /*
3 ** This program attempts to test the correctness of some facets of the
4 ** LSM database library. Specifically, that the contents of the database
5 ** are maintained correctly during a series of inserts and deletes.
6 */
7
8
9 #include "lsmtest_tdb.h"
10 #include "lsm.h"
11
12 #include "lsmtest.h"
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <assert.h>
17 #ifndef _WIN32
18 # include <unistd.h>
19 #endif
20 #include <stdio.h>
21
22
23 typedef struct SqlDb SqlDb;
24
error_transaction_function(TestDb * p,int iLevel)25 static int error_transaction_function(TestDb *p, int iLevel){
26 unused_parameter(p);
27 unused_parameter(iLevel);
28 return -1;
29 }
30
31
32 /*************************************************************************
33 ** Begin wrapper for LevelDB.
34 */
35 #ifdef HAVE_LEVELDB
36
37 #include <leveldb/c.h>
38
39 typedef struct LevelDb LevelDb;
40 struct LevelDb {
41 TestDb base;
42 leveldb_t *db;
43 leveldb_options_t *pOpt;
44 leveldb_writeoptions_t *pWriteOpt;
45 leveldb_readoptions_t *pReadOpt;
46
47 char *pVal;
48 };
49
test_leveldb_close(TestDb * pTestDb)50 static int test_leveldb_close(TestDb *pTestDb){
51 LevelDb *pDb = (LevelDb *)pTestDb;
52
53 leveldb_close(pDb->db);
54 leveldb_writeoptions_destroy(pDb->pWriteOpt);
55 leveldb_readoptions_destroy(pDb->pReadOpt);
56 leveldb_options_destroy(pDb->pOpt);
57 free(pDb->pVal);
58 free(pDb);
59
60 return 0;
61 }
62
test_leveldb_write(TestDb * pTestDb,void * pKey,int nKey,void * pVal,int nVal)63 static int test_leveldb_write(
64 TestDb *pTestDb,
65 void *pKey,
66 int nKey,
67 void *pVal,
68 int nVal
69 ){
70 LevelDb *pDb = (LevelDb *)pTestDb;
71 char *zErr = 0;
72 leveldb_put(pDb->db, pDb->pWriteOpt, pKey, nKey, pVal, nVal, &zErr);
73 return (zErr!=0);
74 }
75
test_leveldb_delete(TestDb * pTestDb,void * pKey,int nKey)76 static int test_leveldb_delete(TestDb *pTestDb, void *pKey, int nKey){
77 LevelDb *pDb = (LevelDb *)pTestDb;
78 char *zErr = 0;
79 leveldb_delete(pDb->db, pDb->pWriteOpt, pKey, nKey, &zErr);
80 return (zErr!=0);
81 }
82
test_leveldb_fetch(TestDb * pTestDb,void * pKey,int nKey,void ** ppVal,int * pnVal)83 static int test_leveldb_fetch(
84 TestDb *pTestDb,
85 void *pKey,
86 int nKey,
87 void **ppVal,
88 int *pnVal
89 ){
90 LevelDb *pDb = (LevelDb *)pTestDb;
91 char *zErr = 0;
92 size_t nVal = 0;
93
94 if( pKey==0 ) return 0;
95 free(pDb->pVal);
96 pDb->pVal = leveldb_get(pDb->db, pDb->pReadOpt, pKey, nKey, &nVal, &zErr);
97 *ppVal = (void *)(pDb->pVal);
98 if( pDb->pVal==0 ){
99 *pnVal = -1;
100 }else{
101 *pnVal = (int)nVal;
102 }
103
104 return (zErr!=0);
105 }
106
test_leveldb_scan(TestDb * pTestDb,void * pCtx,int bReverse,void * pKey1,int nKey1,void * pKey2,int nKey2,void (* xCallback)(void *,void *,int,void *,int))107 static int test_leveldb_scan(
108 TestDb *pTestDb,
109 void *pCtx,
110 int bReverse,
111 void *pKey1, int nKey1, /* Start of search */
112 void *pKey2, int nKey2, /* End of search */
113 void (*xCallback)(void *, void *, int , void *, int)
114 ){
115 LevelDb *pDb = (LevelDb *)pTestDb;
116 leveldb_iterator_t *iter;
117
118 iter = leveldb_create_iterator(pDb->db, pDb->pReadOpt);
119
120 if( bReverse==0 ){
121 if( pKey1 ){
122 leveldb_iter_seek(iter, pKey1, nKey1);
123 }else{
124 leveldb_iter_seek_to_first(iter);
125 }
126 }else{
127 if( pKey2 ){
128 leveldb_iter_seek(iter, pKey2, nKey2);
129
130 if( leveldb_iter_valid(iter)==0 ){
131 leveldb_iter_seek_to_last(iter);
132 }else{
133 const char *k; size_t n;
134 int res;
135 k = leveldb_iter_key(iter, &n);
136 res = memcmp(k, pKey2, MIN(n, nKey2));
137 if( res==0 ) res = n - nKey2;
138 assert( res>=0 );
139 if( res>0 ){
140 leveldb_iter_prev(iter);
141 }
142 }
143 }else{
144 leveldb_iter_seek_to_last(iter);
145 }
146 }
147
148
149 while( leveldb_iter_valid(iter) ){
150 const char *k; size_t n;
151 const char *v; size_t n2;
152 int res;
153
154 k = leveldb_iter_key(iter, &n);
155 if( bReverse==0 && pKey2 ){
156 res = memcmp(k, pKey2, MIN(n, nKey2));
157 if( res==0 ) res = n - nKey2;
158 if( res>0 ) break;
159 }
160 if( bReverse!=0 && pKey1 ){
161 res = memcmp(k, pKey1, MIN(n, nKey1));
162 if( res==0 ) res = n - nKey1;
163 if( res<0 ) break;
164 }
165
166 v = leveldb_iter_value(iter, &n2);
167
168 xCallback(pCtx, (void *)k, n, (void *)v, n2);
169
170 if( bReverse==0 ){
171 leveldb_iter_next(iter);
172 }else{
173 leveldb_iter_prev(iter);
174 }
175 }
176
177 leveldb_iter_destroy(iter);
178 return 0;
179 }
180
test_leveldb_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)181 static int test_leveldb_open(
182 const char *zSpec,
183 const char *zFilename,
184 int bClear,
185 TestDb **ppDb
186 ){
187 static const DatabaseMethods LeveldbMethods = {
188 test_leveldb_close,
189 test_leveldb_write,
190 test_leveldb_delete,
191 0,
192 test_leveldb_fetch,
193 test_leveldb_scan,
194 error_transaction_function,
195 error_transaction_function,
196 error_transaction_function
197 };
198
199 LevelDb *pLevelDb;
200 char *zErr = 0;
201
202 if( bClear ){
203 char *zCmd = sqlite3_mprintf("rm -rf %s\n", zFilename);
204 system(zCmd);
205 sqlite3_free(zCmd);
206 }
207
208 pLevelDb = (LevelDb *)malloc(sizeof(LevelDb));
209 memset(pLevelDb, 0, sizeof(LevelDb));
210
211 pLevelDb->pOpt = leveldb_options_create();
212 leveldb_options_set_create_if_missing(pLevelDb->pOpt, 1);
213 pLevelDb->pWriteOpt = leveldb_writeoptions_create();
214 pLevelDb->pReadOpt = leveldb_readoptions_create();
215
216 pLevelDb->db = leveldb_open(pLevelDb->pOpt, zFilename, &zErr);
217
218 if( zErr ){
219 test_leveldb_close((TestDb *)pLevelDb);
220 *ppDb = 0;
221 return 1;
222 }
223
224 *ppDb = (TestDb *)pLevelDb;
225 pLevelDb->base.pMethods = &LeveldbMethods;
226 return 0;
227 }
228 #endif /* HAVE_LEVELDB */
229 /*
230 ** End wrapper for LevelDB.
231 *************************************************************************/
232
233 #ifdef HAVE_KYOTOCABINET
kc_close(TestDb * pTestDb)234 static int kc_close(TestDb *pTestDb){
235 return test_kc_close(pTestDb);
236 }
237
kc_write(TestDb * pTestDb,void * pKey,int nKey,void * pVal,int nVal)238 static int kc_write(
239 TestDb *pTestDb,
240 void *pKey,
241 int nKey,
242 void *pVal,
243 int nVal
244 ){
245 return test_kc_write(pTestDb, pKey, nKey, pVal, nVal);
246 }
247
kc_delete(TestDb * pTestDb,void * pKey,int nKey)248 static int kc_delete(TestDb *pTestDb, void *pKey, int nKey){
249 return test_kc_delete(pTestDb, pKey, nKey);
250 }
251
kc_delete_range(TestDb * pTestDb,void * pKey1,int nKey1,void * pKey2,int nKey2)252 static int kc_delete_range(
253 TestDb *pTestDb,
254 void *pKey1, int nKey1,
255 void *pKey2, int nKey2
256 ){
257 return test_kc_delete_range(pTestDb, pKey1, nKey1, pKey2, nKey2);
258 }
259
kc_fetch(TestDb * pTestDb,void * pKey,int nKey,void ** ppVal,int * pnVal)260 static int kc_fetch(
261 TestDb *pTestDb,
262 void *pKey,
263 int nKey,
264 void **ppVal,
265 int *pnVal
266 ){
267 if( pKey==0 ) return LSM_OK;
268 return test_kc_fetch(pTestDb, pKey, nKey, ppVal, pnVal);
269 }
270
kc_scan(TestDb * pTestDb,void * pCtx,int bReverse,void * pFirst,int nFirst,void * pLast,int nLast,void (* xCallback)(void *,void *,int,void *,int))271 static int kc_scan(
272 TestDb *pTestDb,
273 void *pCtx,
274 int bReverse,
275 void *pFirst, int nFirst,
276 void *pLast, int nLast,
277 void (*xCallback)(void *, void *, int , void *, int)
278 ){
279 return test_kc_scan(
280 pTestDb, pCtx, bReverse, pFirst, nFirst, pLast, nLast, xCallback
281 );
282 }
283
kc_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)284 static int kc_open(
285 const char *zSpec,
286 const char *zFilename,
287 int bClear,
288 TestDb **ppDb
289 ){
290 static const DatabaseMethods KcdbMethods = {
291 kc_close,
292 kc_write,
293 kc_delete,
294 kc_delete_range,
295 kc_fetch,
296 kc_scan,
297 error_transaction_function,
298 error_transaction_function,
299 error_transaction_function
300 };
301
302 int rc;
303 TestDb *pTestDb = 0;
304
305 rc = test_kc_open(zFilename, bClear, &pTestDb);
306 if( rc!=0 ){
307 *ppDb = 0;
308 return rc;
309 }
310 pTestDb->pMethods = &KcdbMethods;
311 *ppDb = pTestDb;
312 return 0;
313 }
314 #endif /* HAVE_KYOTOCABINET */
315 /*
316 ** End wrapper for Kyoto cabinet.
317 *************************************************************************/
318
319 #ifdef HAVE_MDB
mdb_close(TestDb * pTestDb)320 static int mdb_close(TestDb *pTestDb){
321 return test_mdb_close(pTestDb);
322 }
323
mdb_write(TestDb * pTestDb,void * pKey,int nKey,void * pVal,int nVal)324 static int mdb_write(
325 TestDb *pTestDb,
326 void *pKey,
327 int nKey,
328 void *pVal,
329 int nVal
330 ){
331 return test_mdb_write(pTestDb, pKey, nKey, pVal, nVal);
332 }
333
mdb_delete(TestDb * pTestDb,void * pKey,int nKey)334 static int mdb_delete(TestDb *pTestDb, void *pKey, int nKey){
335 return test_mdb_delete(pTestDb, pKey, nKey);
336 }
337
mdb_fetch(TestDb * pTestDb,void * pKey,int nKey,void ** ppVal,int * pnVal)338 static int mdb_fetch(
339 TestDb *pTestDb,
340 void *pKey,
341 int nKey,
342 void **ppVal,
343 int *pnVal
344 ){
345 if( pKey==0 ) return LSM_OK;
346 return test_mdb_fetch(pTestDb, pKey, nKey, ppVal, pnVal);
347 }
348
mdb_scan(TestDb * pTestDb,void * pCtx,int bReverse,void * pFirst,int nFirst,void * pLast,int nLast,void (* xCallback)(void *,void *,int,void *,int))349 static int mdb_scan(
350 TestDb *pTestDb,
351 void *pCtx,
352 int bReverse,
353 void *pFirst, int nFirst,
354 void *pLast, int nLast,
355 void (*xCallback)(void *, void *, int , void *, int)
356 ){
357 return test_mdb_scan(
358 pTestDb, pCtx, bReverse, pFirst, nFirst, pLast, nLast, xCallback
359 );
360 }
361
mdb_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)362 static int mdb_open(
363 const char *zSpec,
364 const char *zFilename,
365 int bClear,
366 TestDb **ppDb
367 ){
368 static const DatabaseMethods KcdbMethods = {
369 mdb_close,
370 mdb_write,
371 mdb_delete,
372 0,
373 mdb_fetch,
374 mdb_scan,
375 error_transaction_function,
376 error_transaction_function,
377 error_transaction_function
378 };
379
380 int rc;
381 TestDb *pTestDb = 0;
382
383 rc = test_mdb_open(zSpec, zFilename, bClear, &pTestDb);
384 if( rc!=0 ){
385 *ppDb = 0;
386 return rc;
387 }
388 pTestDb->pMethods = &KcdbMethods;
389 *ppDb = pTestDb;
390 return 0;
391 }
392 #endif /* HAVE_MDB */
393
394 /*************************************************************************
395 ** Begin wrapper for SQLite.
396 */
397
398 /*
399 ** nOpenTrans:
400 ** The number of open nested transactions, in the same sense as used
401 ** by the tdb_begin/commit/rollback and SQLite 4 KV interfaces. If this
402 ** value is 0, there are no transactions open at all. If it is 1, then
403 ** there is a read transaction. If it is 2 or greater, then there are
404 ** (nOpenTrans-1) nested write transactions open.
405 */
406 struct SqlDb {
407 TestDb base;
408 sqlite3 *db;
409 sqlite3_stmt *pInsert;
410 sqlite3_stmt *pDelete;
411 sqlite3_stmt *pDeleteRange;
412 sqlite3_stmt *pFetch;
413 sqlite3_stmt *apScan[8];
414
415 int nOpenTrans;
416
417 /* Used by sql_fetch() to allocate space for results */
418 int nAlloc;
419 u8 *aAlloc;
420 };
421
sql_close(TestDb * pTestDb)422 static int sql_close(TestDb *pTestDb){
423 SqlDb *pDb = (SqlDb *)pTestDb;
424 sqlite3_finalize(pDb->pInsert);
425 sqlite3_finalize(pDb->pDelete);
426 sqlite3_finalize(pDb->pDeleteRange);
427 sqlite3_finalize(pDb->pFetch);
428 sqlite3_finalize(pDb->apScan[0]);
429 sqlite3_finalize(pDb->apScan[1]);
430 sqlite3_finalize(pDb->apScan[2]);
431 sqlite3_finalize(pDb->apScan[3]);
432 sqlite3_finalize(pDb->apScan[4]);
433 sqlite3_finalize(pDb->apScan[5]);
434 sqlite3_finalize(pDb->apScan[6]);
435 sqlite3_finalize(pDb->apScan[7]);
436 sqlite3_close(pDb->db);
437 free((char *)pDb->aAlloc);
438 free((char *)pDb);
439 return SQLITE_OK;
440 }
441
sql_write(TestDb * pTestDb,void * pKey,int nKey,void * pVal,int nVal)442 static int sql_write(
443 TestDb *pTestDb,
444 void *pKey,
445 int nKey,
446 void *pVal,
447 int nVal
448 ){
449 SqlDb *pDb = (SqlDb *)pTestDb;
450 sqlite3_bind_blob(pDb->pInsert, 1, pKey, nKey, SQLITE_STATIC);
451 sqlite3_bind_blob(pDb->pInsert, 2, pVal, nVal, SQLITE_STATIC);
452 sqlite3_step(pDb->pInsert);
453 return sqlite3_reset(pDb->pInsert);
454 }
455
sql_delete(TestDb * pTestDb,void * pKey,int nKey)456 static int sql_delete(TestDb *pTestDb, void *pKey, int nKey){
457 SqlDb *pDb = (SqlDb *)pTestDb;
458 sqlite3_bind_blob(pDb->pDelete, 1, pKey, nKey, SQLITE_STATIC);
459 sqlite3_step(pDb->pDelete);
460 return sqlite3_reset(pDb->pDelete);
461 }
462
sql_delete_range(TestDb * pTestDb,void * pKey1,int nKey1,void * pKey2,int nKey2)463 static int sql_delete_range(
464 TestDb *pTestDb,
465 void *pKey1, int nKey1,
466 void *pKey2, int nKey2
467 ){
468 SqlDb *pDb = (SqlDb *)pTestDb;
469 sqlite3_bind_blob(pDb->pDeleteRange, 1, pKey1, nKey1, SQLITE_STATIC);
470 sqlite3_bind_blob(pDb->pDeleteRange, 2, pKey2, nKey2, SQLITE_STATIC);
471 sqlite3_step(pDb->pDeleteRange);
472 return sqlite3_reset(pDb->pDeleteRange);
473 }
474
sql_fetch(TestDb * pTestDb,void * pKey,int nKey,void ** ppVal,int * pnVal)475 static int sql_fetch(
476 TestDb *pTestDb,
477 void *pKey,
478 int nKey,
479 void **ppVal,
480 int *pnVal
481 ){
482 SqlDb *pDb = (SqlDb *)pTestDb;
483 int rc;
484
485 sqlite3_reset(pDb->pFetch);
486 if( pKey==0 ){
487 assert( ppVal==0 );
488 assert( pnVal==0 );
489 return LSM_OK;
490 }
491
492 sqlite3_bind_blob(pDb->pFetch, 1, pKey, nKey, SQLITE_STATIC);
493 rc = sqlite3_step(pDb->pFetch);
494 if( rc==SQLITE_ROW ){
495 int nVal = sqlite3_column_bytes(pDb->pFetch, 0);
496 u8 *aVal = (void *)sqlite3_column_blob(pDb->pFetch, 0);
497
498 if( nVal>pDb->nAlloc ){
499 free(pDb->aAlloc);
500 pDb->aAlloc = (u8 *)malloc(nVal*2);
501 pDb->nAlloc = nVal*2;
502 }
503 memcpy(pDb->aAlloc, aVal, nVal);
504 *pnVal = nVal;
505 *ppVal = (void *)pDb->aAlloc;
506 }else{
507 *pnVal = -1;
508 *ppVal = 0;
509 }
510
511 rc = sqlite3_reset(pDb->pFetch);
512 return rc;
513 }
514
sql_scan(TestDb * pTestDb,void * pCtx,int bReverse,void * pFirst,int nFirst,void * pLast,int nLast,void (* xCallback)(void *,void *,int,void *,int))515 static int sql_scan(
516 TestDb *pTestDb,
517 void *pCtx,
518 int bReverse,
519 void *pFirst, int nFirst,
520 void *pLast, int nLast,
521 void (*xCallback)(void *, void *, int , void *, int)
522 ){
523 SqlDb *pDb = (SqlDb *)pTestDb;
524 sqlite3_stmt *pScan;
525
526 assert( bReverse==1 || bReverse==0 );
527 pScan = pDb->apScan[(pFirst==0) + (pLast==0)*2 + bReverse*4];
528
529 if( pFirst ) sqlite3_bind_blob(pScan, 1, pFirst, nFirst, SQLITE_STATIC);
530 if( pLast ) sqlite3_bind_blob(pScan, 2, pLast, nLast, SQLITE_STATIC);
531
532 while( SQLITE_ROW==sqlite3_step(pScan) ){
533 void *pKey; int nKey;
534 void *pVal; int nVal;
535
536 nKey = sqlite3_column_bytes(pScan, 0);
537 pKey = (void *)sqlite3_column_blob(pScan, 0);
538 nVal = sqlite3_column_bytes(pScan, 1);
539 pVal = (void *)sqlite3_column_blob(pScan, 1);
540
541 xCallback(pCtx, pKey, nKey, pVal, nVal);
542 }
543 return sqlite3_reset(pScan);
544 }
545
sql_begin(TestDb * pTestDb,int iLevel)546 static int sql_begin(TestDb *pTestDb, int iLevel){
547 int i;
548 SqlDb *pDb = (SqlDb *)pTestDb;
549
550 /* iLevel==0 is a no-op */
551 if( iLevel==0 ) return 0;
552
553 /* If there are no transactions at all open, open a read transaction. */
554 if( pDb->nOpenTrans==0 ){
555 int rc = sqlite3_exec(pDb->db,
556 "BEGIN; SELECT * FROM sqlite_schema LIMIT 1;" , 0, 0, 0
557 );
558 if( rc!=0 ) return rc;
559 pDb->nOpenTrans = 1;
560 }
561
562 /* Open any required write transactions */
563 for(i=pDb->nOpenTrans; i<iLevel; i++){
564 char *zSql = sqlite3_mprintf("SAVEPOINT x%d", i);
565 int rc = sqlite3_exec(pDb->db, zSql, 0, 0, 0);
566 sqlite3_free(zSql);
567 if( rc!=SQLITE_OK ) return rc;
568 }
569
570 pDb->nOpenTrans = iLevel;
571 return 0;
572 }
573
sql_commit(TestDb * pTestDb,int iLevel)574 static int sql_commit(TestDb *pTestDb, int iLevel){
575 SqlDb *pDb = (SqlDb *)pTestDb;
576 assert( iLevel>=0 );
577
578 /* Close the read transaction if requested. */
579 if( pDb->nOpenTrans>=1 && iLevel==0 ){
580 int rc = sqlite3_exec(pDb->db, "COMMIT", 0, 0, 0);
581 if( rc!=0 ) return rc;
582 pDb->nOpenTrans = 0;
583 }
584
585 /* Close write transactions as required */
586 if( pDb->nOpenTrans>iLevel ){
587 char *zSql = sqlite3_mprintf("RELEASE x%d", iLevel);
588 int rc = sqlite3_exec(pDb->db, zSql, 0, 0, 0);
589 sqlite3_free(zSql);
590 if( rc!=0 ) return rc;
591 }
592
593 pDb->nOpenTrans = iLevel;
594 return 0;
595 }
596
sql_rollback(TestDb * pTestDb,int iLevel)597 static int sql_rollback(TestDb *pTestDb, int iLevel){
598 SqlDb *pDb = (SqlDb *)pTestDb;
599 assert( iLevel>=0 );
600
601 if( pDb->nOpenTrans>=1 && iLevel==0 ){
602 /* Close the read transaction if requested. */
603 int rc = sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0);
604 if( rc!=0 ) return rc;
605 }else if( pDb->nOpenTrans>1 && iLevel==1 ){
606 /* Or, rollback and close the top-level write transaction */
607 int rc = sqlite3_exec(pDb->db, "ROLLBACK TO x1; RELEASE x1;", 0, 0, 0);
608 if( rc!=0 ) return rc;
609 }else{
610 /* Or, just roll back some nested transactions */
611 char *zSql = sqlite3_mprintf("ROLLBACK TO x%d", iLevel-1);
612 int rc = sqlite3_exec(pDb->db, zSql, 0, 0, 0);
613 sqlite3_free(zSql);
614 if( rc!=0 ) return rc;
615 }
616
617 pDb->nOpenTrans = iLevel;
618 return 0;
619 }
620
sql_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)621 static int sql_open(
622 const char *zSpec,
623 const char *zFilename,
624 int bClear,
625 TestDb **ppDb
626 ){
627 static const DatabaseMethods SqlMethods = {
628 sql_close,
629 sql_write,
630 sql_delete,
631 sql_delete_range,
632 sql_fetch,
633 sql_scan,
634 sql_begin,
635 sql_commit,
636 sql_rollback
637 };
638 const char *zCreate = "CREATE TABLE IF NOT EXISTS t1(k PRIMARY KEY, v)";
639 const char *zInsert = "REPLACE INTO t1 VALUES(?, ?)";
640 const char *zDelete = "DELETE FROM t1 WHERE k = ?";
641 const char *zRange = "DELETE FROM t1 WHERE k>? AND k<?";
642 const char *zFetch = "SELECT v FROM t1 WHERE k = ?";
643
644 const char *zScan0 = "SELECT * FROM t1 WHERE k BETWEEN ?1 AND ?2 ORDER BY k";
645 const char *zScan1 = "SELECT * FROM t1 WHERE k <= ?2 ORDER BY k";
646 const char *zScan2 = "SELECT * FROM t1 WHERE k >= ?1 ORDER BY k";
647 const char *zScan3 = "SELECT * FROM t1 ORDER BY k";
648
649 const char *zScan4 =
650 "SELECT * FROM t1 WHERE k BETWEEN ?1 AND ?2 ORDER BY k DESC";
651 const char *zScan5 = "SELECT * FROM t1 WHERE k <= ?2 ORDER BY k DESC";
652 const char *zScan6 = "SELECT * FROM t1 WHERE k >= ?1 ORDER BY k DESC";
653 const char *zScan7 = "SELECT * FROM t1 ORDER BY k DESC";
654
655 int rc;
656 SqlDb *pDb;
657 char *zPragma;
658
659 if( bClear && zFilename && zFilename[0] ){
660 unlink(zFilename);
661 }
662
663 pDb = (SqlDb *)malloc(sizeof(SqlDb));
664 memset(pDb, 0, sizeof(SqlDb));
665 pDb->base.pMethods = &SqlMethods;
666
667 if( 0!=(rc = sqlite3_open(zFilename, &pDb->db))
668 || 0!=(rc = sqlite3_exec(pDb->db, zCreate, 0, 0, 0))
669 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zInsert, -1, &pDb->pInsert, 0))
670 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zDelete, -1, &pDb->pDelete, 0))
671 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zRange, -1, &pDb->pDeleteRange, 0))
672 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zFetch, -1, &pDb->pFetch, 0))
673 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan0, -1, &pDb->apScan[0], 0))
674 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan1, -1, &pDb->apScan[1], 0))
675 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan2, -1, &pDb->apScan[2], 0))
676 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan3, -1, &pDb->apScan[3], 0))
677 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan4, -1, &pDb->apScan[4], 0))
678 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan5, -1, &pDb->apScan[5], 0))
679 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan6, -1, &pDb->apScan[6], 0))
680 || 0!=(rc = sqlite3_prepare_v2(pDb->db, zScan7, -1, &pDb->apScan[7], 0))
681 ){
682 *ppDb = 0;
683 sql_close((TestDb *)pDb);
684 return rc;
685 }
686
687 zPragma = sqlite3_mprintf("PRAGMA page_size=%d", TESTDB_DEFAULT_PAGE_SIZE);
688 sqlite3_exec(pDb->db, zPragma, 0, 0, 0);
689 sqlite3_free(zPragma);
690 zPragma = sqlite3_mprintf("PRAGMA cache_size=%d", TESTDB_DEFAULT_CACHE_SIZE);
691 sqlite3_exec(pDb->db, zPragma, 0, 0, 0);
692 sqlite3_free(zPragma);
693
694 /* sqlite3_exec(pDb->db, "PRAGMA locking_mode=EXCLUSIVE", 0, 0, 0); */
695 sqlite3_exec(pDb->db, "PRAGMA synchronous=OFF", 0, 0, 0);
696 sqlite3_exec(pDb->db, "PRAGMA journal_mode=WAL", 0, 0, 0);
697 sqlite3_exec(pDb->db, "PRAGMA wal_autocheckpoint=4096", 0, 0, 0);
698 if( zSpec ){
699 rc = sqlite3_exec(pDb->db, zSpec, 0, 0, 0);
700 if( rc!=SQLITE_OK ){
701 sql_close((TestDb *)pDb);
702 return rc;
703 }
704 }
705
706 *ppDb = (TestDb *)pDb;
707 return 0;
708 }
709 /*
710 ** End wrapper for SQLite.
711 *************************************************************************/
712
713 /*************************************************************************
714 ** Begin exported functions.
715 */
716 static struct Lib {
717 const char *zName;
718 const char *zDefaultDb;
719 int (*xOpen)(const char *, const char *zFilename, int bClear, TestDb **ppDb);
720 } aLib[] = {
721 { "sqlite3", "testdb.sqlite", sql_open },
722 { "lsm_small", "testdb.lsm_small", test_lsm_small_open },
723 { "lsm_lomem", "testdb.lsm_lomem", test_lsm_lomem_open },
724 { "lsm_lomem2", "testdb.lsm_lomem2", test_lsm_lomem2_open },
725 #ifdef HAVE_ZLIB
726 { "lsm_zip", "testdb.lsm_zip", test_lsm_zip_open },
727 #endif
728 { "lsm", "testdb.lsm", test_lsm_open },
729 #ifdef LSM_MUTEX_PTHREADS
730 { "lsm_mt2", "testdb.lsm_mt2", test_lsm_mt2 },
731 { "lsm_mt3", "testdb.lsm_mt3", test_lsm_mt3 },
732 #endif
733 #ifdef HAVE_LEVELDB
734 { "leveldb", "testdb.leveldb", test_leveldb_open },
735 #endif
736 #ifdef HAVE_KYOTOCABINET
737 { "kyotocabinet", "testdb.kc", kc_open },
738 #endif
739 #ifdef HAVE_MDB
740 { "mdb", "./testdb.mdb", mdb_open }
741 #endif
742 };
743
tdb_system_name(int i)744 const char *tdb_system_name(int i){
745 if( i<0 || i>=ArraySize(aLib) ) return 0;
746 return aLib[i].zName;
747 }
748
tdb_default_db(const char * zSys)749 const char *tdb_default_db(const char *zSys){
750 int i;
751 for(i=0; i<ArraySize(aLib); i++){
752 if( strcmp(aLib[i].zName, zSys)==0 ) return aLib[i].zDefaultDb;
753 }
754 return 0;
755 }
756
tdb_open(const char * zLib,const char * zDb,int bClear,TestDb ** ppDb)757 int tdb_open(const char *zLib, const char *zDb, int bClear, TestDb **ppDb){
758 int i;
759 int rc = 1;
760 const char *zSpec = 0;
761
762 int nLib = 0;
763 while( zLib[nLib] && zLib[nLib]!=' ' ){
764 nLib++;
765 }
766 zSpec = &zLib[nLib];
767 while( *zSpec==' ' ) zSpec++;
768 if( *zSpec=='\0' ) zSpec = 0;
769
770 for(i=0; i<ArraySize(aLib); i++){
771 if( (int)strlen(aLib[i].zName)==nLib
772 && 0==memcmp(zLib, aLib[i].zName, nLib) ){
773 rc = aLib[i].xOpen(zSpec, (zDb ? zDb : aLib[i].zDefaultDb), bClear, ppDb);
774 if( rc==0 ){
775 (*ppDb)->zLibrary = aLib[i].zName;
776 }
777 break;
778 }
779 }
780
781 if( rc ){
782 /* Failed to find the requested database library. Return an error. */
783 *ppDb = 0;
784 }
785 return rc;
786 }
787
tdb_close(TestDb * pDb)788 int tdb_close(TestDb *pDb){
789 if( pDb ){
790 return pDb->pMethods->xClose(pDb);
791 }
792 return 0;
793 }
794
tdb_write(TestDb * pDb,void * pKey,int nKey,void * pVal,int nVal)795 int tdb_write(TestDb *pDb, void *pKey, int nKey, void *pVal, int nVal){
796 return pDb->pMethods->xWrite(pDb, pKey, nKey, pVal, nVal);
797 }
798
tdb_delete(TestDb * pDb,void * pKey,int nKey)799 int tdb_delete(TestDb *pDb, void *pKey, int nKey){
800 return pDb->pMethods->xDelete(pDb, pKey, nKey);
801 }
802
tdb_delete_range(TestDb * pDb,void * pKey1,int nKey1,void * pKey2,int nKey2)803 int tdb_delete_range(
804 TestDb *pDb, void *pKey1, int nKey1, void *pKey2, int nKey2
805 ){
806 return pDb->pMethods->xDeleteRange(pDb, pKey1, nKey1, pKey2, nKey2);
807 }
808
tdb_fetch(TestDb * pDb,void * pKey,int nKey,void ** ppVal,int * pnVal)809 int tdb_fetch(TestDb *pDb, void *pKey, int nKey, void **ppVal, int *pnVal){
810 return pDb->pMethods->xFetch(pDb, pKey, nKey, ppVal, pnVal);
811 }
812
tdb_scan(TestDb * pDb,void * pCtx,int bReverse,void * pKey1,int nKey1,void * pKey2,int nKey2,void (* xCallback)(void * pCtx,void * pKey,int nKey,void * pVal,int nVal))813 int tdb_scan(
814 TestDb *pDb, /* Database handle */
815 void *pCtx, /* Context pointer to pass to xCallback */
816 int bReverse, /* True to scan in reverse order */
817 void *pKey1, int nKey1, /* Start of search */
818 void *pKey2, int nKey2, /* End of search */
819 void (*xCallback)(void *pCtx, void *pKey, int nKey, void *pVal, int nVal)
820 ){
821 return pDb->pMethods->xScan(
822 pDb, pCtx, bReverse, pKey1, nKey1, pKey2, nKey2, xCallback
823 );
824 }
825
tdb_begin(TestDb * pDb,int iLevel)826 int tdb_begin(TestDb *pDb, int iLevel){
827 return pDb->pMethods->xBegin(pDb, iLevel);
828 }
tdb_commit(TestDb * pDb,int iLevel)829 int tdb_commit(TestDb *pDb, int iLevel){
830 return pDb->pMethods->xCommit(pDb, iLevel);
831 }
tdb_rollback(TestDb * pDb,int iLevel)832 int tdb_rollback(TestDb *pDb, int iLevel){
833 return pDb->pMethods->xRollback(pDb, iLevel);
834 }
835
tdb_transaction_support(TestDb * pDb)836 int tdb_transaction_support(TestDb *pDb){
837 return (pDb->pMethods->xBegin != error_transaction_function);
838 }
839
tdb_library_name(TestDb * pDb)840 const char *tdb_library_name(TestDb *pDb){
841 return pDb->zLibrary;
842 }
843
844 /*
845 ** End exported functions.
846 *************************************************************************/
847