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 *************************************************************************/