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