modernc.org/cc@v1.0.1/v2/testdata/_sqlite/ext/lsm1/lsm-test/lsmtest_tdb.c (about)

     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  
    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  
    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  
    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  
    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  
    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  
   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  
   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
   234  static int kc_close(TestDb *pTestDb){
   235    return test_kc_close(pTestDb);
   236  }
   237  
   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  
   248  static int kc_delete(TestDb *pTestDb, void *pKey, int nKey){
   249    return test_kc_delete(pTestDb, pKey, nKey);
   250  }
   251  
   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  
   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  
   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  
   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
   320  static int mdb_close(TestDb *pTestDb){
   321    return test_mdb_close(pTestDb);
   322  }
   323  
   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  
   334  static int mdb_delete(TestDb *pTestDb, void *pKey, int nKey){
   335    return test_mdb_delete(pTestDb, pKey, nKey);
   336  }
   337  
   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  
   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  
   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  
   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  
   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  
   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  
   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  
   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  
   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  
   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_master 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  
   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  
   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  
   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  #ifdef HAVE_ZLIB
   725    { "lsm_zip",      "testdb.lsm_zip",   test_lsm_zip_open },
   726  #endif
   727    { "lsm",          "testdb.lsm",       test_lsm_open },
   728  #ifdef LSM_MUTEX_PTHREADS
   729    { "lsm_mt2",      "testdb.lsm_mt2",   test_lsm_mt2 },
   730    { "lsm_mt3",      "testdb.lsm_mt3",   test_lsm_mt3 },
   731  #endif
   732  #ifdef HAVE_LEVELDB
   733    { "leveldb",      "testdb.leveldb",   test_leveldb_open },
   734  #endif
   735  #ifdef HAVE_KYOTOCABINET
   736    { "kyotocabinet", "testdb.kc",        kc_open },
   737  #endif
   738  #ifdef HAVE_MDB
   739    { "mdb", "./testdb.mdb",        mdb_open }
   740  #endif
   741  };
   742  
   743  const char *tdb_system_name(int i){
   744    if( i<0 || i>=ArraySize(aLib) ) return 0;
   745    return aLib[i].zName;
   746  }
   747  
   748  const char *tdb_default_db(const char *zSys){
   749    int i;
   750    for(i=0; i<ArraySize(aLib); i++){
   751      if( strcmp(aLib[i].zName, zSys)==0 ) return aLib[i].zDefaultDb;
   752    }
   753    return 0;
   754  }
   755  
   756  int tdb_open(const char *zLib, const char *zDb, int bClear, TestDb **ppDb){
   757    int i;
   758    int rc = 1;
   759    const char *zSpec = 0;
   760  
   761    int nLib = 0;
   762    while( zLib[nLib] && zLib[nLib]!=' ' ){
   763      nLib++;
   764    }
   765    zSpec = &zLib[nLib];
   766    while( *zSpec==' ' ) zSpec++;
   767    if( *zSpec=='\0' ) zSpec = 0;
   768  
   769    for(i=0; i<ArraySize(aLib); i++){
   770      if( (int)strlen(aLib[i].zName)==nLib
   771          && 0==memcmp(zLib, aLib[i].zName, nLib) ){
   772        rc = aLib[i].xOpen(zSpec, (zDb ? zDb : aLib[i].zDefaultDb), bClear, ppDb);
   773        if( rc==0 ){
   774          (*ppDb)->zLibrary = aLib[i].zName;
   775        }
   776        break;
   777      }
   778    }
   779  
   780    if( rc ){
   781      /* Failed to find the requested database library. Return an error. */
   782      *ppDb = 0;
   783    }
   784    return rc;
   785  }
   786  
   787  int tdb_close(TestDb *pDb){
   788    if( pDb ){
   789      return pDb->pMethods->xClose(pDb);
   790    }
   791    return 0;
   792  }
   793  
   794  int tdb_write(TestDb *pDb, void *pKey, int nKey, void *pVal, int nVal){
   795    return pDb->pMethods->xWrite(pDb, pKey, nKey, pVal, nVal);
   796  }
   797  
   798  int tdb_delete(TestDb *pDb, void *pKey, int nKey){
   799    return pDb->pMethods->xDelete(pDb, pKey, nKey);
   800  }
   801  
   802  int tdb_delete_range(
   803      TestDb *pDb, void *pKey1, int nKey1, void *pKey2, int nKey2
   804  ){
   805    return pDb->pMethods->xDeleteRange(pDb, pKey1, nKey1, pKey2, nKey2);
   806  }
   807  
   808  int tdb_fetch(TestDb *pDb, void *pKey, int nKey, void **ppVal, int *pnVal){
   809    return pDb->pMethods->xFetch(pDb, pKey, nKey, ppVal, pnVal);
   810  }
   811  
   812  int tdb_scan(
   813    TestDb *pDb,                    /* Database handle */
   814    void *pCtx,                     /* Context pointer to pass to xCallback */
   815    int bReverse,                   /* True to scan in reverse order */
   816    void *pKey1, int nKey1,         /* Start of search */
   817    void *pKey2, int nKey2,         /* End of search */
   818    void (*xCallback)(void *pCtx, void *pKey, int nKey, void *pVal, int nVal)
   819  ){
   820    return pDb->pMethods->xScan(
   821        pDb, pCtx, bReverse, pKey1, nKey1, pKey2, nKey2, xCallback
   822    );
   823  }
   824  
   825  int tdb_begin(TestDb *pDb, int iLevel){
   826    return pDb->pMethods->xBegin(pDb, iLevel);
   827  }
   828  int tdb_commit(TestDb *pDb, int iLevel){
   829    return pDb->pMethods->xCommit(pDb, iLevel);
   830  }
   831  int tdb_rollback(TestDb *pDb, int iLevel){
   832    return pDb->pMethods->xRollback(pDb, iLevel);
   833  }
   834  
   835  int tdb_transaction_support(TestDb *pDb){
   836    return (pDb->pMethods->xBegin != error_transaction_function);
   837  }
   838  
   839  const char *tdb_library_name(TestDb *pDb){
   840    return pDb->zLibrary;
   841  }
   842  
   843  /* 
   844  ** End exported functions.
   845  *************************************************************************/