Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add miscellaneous test cases to improve coverage of sessions module. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | sessions |
Files: | files | file ages | folders |
SHA1: |
0fac6cfffe628ea02c78ebad06530730 |
User & Date: | dan 2014-08-18 16:03:46.849 |
Context
2014-08-18
| ||
20:08 | Add the "changeset" command-line tool for analyzing and manipulating changesets in files on disk. Add the ".session" command to the command-line tool. (check-in: 31addb627f user: drh tags: sessions) | |
16:03 | Add miscellaneous test cases to improve coverage of sessions module. (check-in: 0fac6cfffe user: dan tags: sessions) | |
13:48 | Merge the latest trunk changes, and in particular the refactoring of the object names in the command-line shell. (check-in: 419d286a2f user: drh tags: sessions) | |
Changes
Changes to ext/session/session1.test.
︙ | ︙ | |||
488 489 490 491 492 493 494 495 496 497 498 499 500 501 | sqlite3session S db main S attach t5 execsql { DELETE FROM t5 } S isempty } {1} do_test 8.4 { S delete } {} #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g); INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1); } do_test 9.2 { | > > > > > > > > > > > > > > > > > > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | sqlite3session S db main S attach t5 execsql { DELETE FROM t5 } S isempty } {1} do_test 8.4 { S delete } {} do_test 8.5 { sqlite3session S db main S attach t5 S attach t6 execsql { INSERT INTO t5 VALUES(1, 2) } S isempty } {0} do_test 8.6 { S delete sqlite3session S db main S attach t5 S attach t6 execsql { INSERT INTO t6 VALUES(1, 2) } S isempty } {0} do_test 8.7 { S delete } {} #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t7(a, b, c, d, e PRIMARY KEY, f, g); INSERT INTO t7 VALUES(1, 1, 1, 1, 1, 1, 1); } do_test 9.2 { |
︙ | ︙ |
Changes to ext/session/sessionB.test.
︙ | ︙ | |||
449 450 451 452 453 454 455 456 457 | db2 close } proc do_patchset_changeset_test {tn initsql args} { foreach tstcmd {patchset changeset} { reset_db execsql $initsql foreach sql $args { set lSql [split $sql ";"] | > > | | 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 | db2 close } proc do_patchset_changeset_test {tn initsql args} { foreach tstcmd {patchset changeset} { reset_db execsql $initsql set x 0 foreach sql $args { incr x set lSql [split $sql ";"] uplevel [list do_patchset_test $tn.$tstcmd.$x $tstcmd $lSql] } } } do_patchset_changeset_test 5.1 { CREATE TABLE t1(a PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 2, 3); |
︙ | ︙ | |||
496 497 498 499 500 501 502 503 504 505 506 | INSERT INTO t2 SELECT NULL, * FROM t1; DELETE FROM t1; INSERT INTO t1 SELECT b, c, d FROM t2; UPDATE t1 SET b = b+1; UPDATE t1 SET b = b+1; UPDATE t1 SET b = b+1; } finish_test | > > > > > > > > > > > | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | INSERT INTO t2 SELECT NULL, * FROM t1; DELETE FROM t1; INSERT INTO t1 SELECT b, c, d FROM t2; UPDATE t1 SET b = b+1; UPDATE t1 SET b = b+1; UPDATE t1 SET b = b+1; } set initsql { CREATE TABLE t1(a, b, c, PRIMARY KEY(c, b)); } for {set i 0} {$i < 1000} {incr i} { append insert "INSERT INTO t1 VALUES($i, $i, $i);" append delete "DELETE FROM t1 WHERE b=$i;" } do_patchset_changeset_test 5.3 \ $initsql $insert $delete \ $insert $delete \ "$insert $delete" \ $delete finish_test |
Changes to ext/session/sessionfault.test.
︙ | ︙ | |||
16 17 18 19 20 21 22 | set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl set testprefix sessionfault | < < | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] session_common.tcl] source $testdir/tester.tcl set testprefix sessionfault forcedelete test.db2 sqlite3 db2 test.db2 do_common_sql { CREATE TABLE t1(a, b, c, PRIMARY KEY(a, b)); INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(4, 5, 6); } |
︙ | ︙ | |||
395 396 397 398 399 400 401 | }] if { [changeset_to_list $::c] != $expected } { error "changeset mismatch" } } } | < < | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | }] if { [changeset_to_list $::c] != $expected } { error "changeset mismatch" } } } faultsim_delete_and_reopen do_test 9.2.prep { execsql { PRAGMA encoding = 'utf16'; CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES('abcdefghij', 'ABCDEFGHIJKLMNOPQRSTUV'); } |
︙ | ︙ | |||
433 434 435 436 437 438 439 440 | {UPDATE t1 0 X. {t abcdefghij t ABCDEFGHIJKLMNOPQRSTUV} {{} {} t xyz}} }] if { [changeset_to_list $::c] != $expected } { error "changeset mismatch" } } } | > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | {UPDATE t1 0 X. {t abcdefghij t ABCDEFGHIJKLMNOPQRSTUV} {{} {} t xyz}} }] if { [changeset_to_list $::c] != $expected } { error "changeset mismatch" } } } #------------------------------------------------------------------------- # Test that if a conflict-handler encounters an OOM in # sqlite3_value_text() but goes on to return SQLITE_CHANGESET_REPLACE # anyway, the OOM is picked up by the sessions module. set bigstr [string repeat abcdefghij 100] faultsim_delete_and_reopen do_test 10.prep.1 { execsql { CREATE TABLE t1(a PRIMARY KEY, b); INSERT INTO t1 VALUES($bigstr, $bigstr); } sqlite3session S db main S attach * execsql { UPDATE t1 SET b = b||'x' } set C [S changeset] S delete execsql { UPDATE t1 SET b = b||'xyz' } } {} faultsim_save_and_close faultsim_restore_and_reopen do_test 10.prep.2 { proc xConflict {args} { return "ABORT" } list [catch { sqlite3changeset_apply db $C xConflict } msg] $msg } {1 SQLITE_ABORT} do_execsql_test 10.prep.3 { SELECT b=$bigstr||'x' FROM t1 } 0 do_test 10.prep.4 { proc xConflict {args} { return "REPLACE" } list [catch { sqlite3changeset_apply db $C xConflict } msg] $msg } {0 {}} do_execsql_test 10.prep.5 { SELECT b=$bigstr||'x' FROM t1 } 1 db close do_faultsim_test 10 -faults oom-tra* -prep { faultsim_restore_and_reopen } -body { sqlite3changeset_apply_replace_all db $::C } -test { faultsim_test_result {0 {}} {1 SQLITE_NOMEM} if {$testrc==0} { if {[db one {SELECT b=$bigstr||'x' FROM t1}]==0} { error "data does not look right" } } } finish_test |
Changes to ext/session/sqlite3session.c.
︙ | ︙ | |||
2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 | */ static int sessionBindValue( sqlite3_stmt *pStmt, /* Statement to bind value to */ int i, /* Parameter number to bind to */ sqlite3_value *pVal /* Value to bind */ ){ int eType = sqlite3_value_type(pVal); if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){ /* This condition occurs when an earlier OOM in a call to ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within | > > > > | | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 | */ static int sessionBindValue( sqlite3_stmt *pStmt, /* Statement to bind value to */ int i, /* Parameter number to bind to */ sqlite3_value *pVal /* Value to bind */ ){ int eType = sqlite3_value_type(pVal); /* COVERAGE: The (pVal->z==0) branch is never true using current versions ** of SQLite. If a malloc fails in an sqlite3_value_xxx() function, either ** the (pVal->z) variable remains as it was or the type of the value is ** set to SQLITE_NULL. */ if( (eType==SQLITE_TEXT || eType==SQLITE_BLOB) && pVal->z==0 ){ /* This condition occurs when an earlier OOM in a call to ** sqlite3_value_text() or sqlite3_value_blob() (perhaps from within ** a conflict-handler) has zeroed the pVal->z pointer. Return NOMEM. */ return SQLITE_NOMEM; } return sqlite3_bind_value(pStmt, i, pVal); } /* ** Iterator pIter must point to an SQLITE_INSERT entry. This function |
︙ | ︙ | |||
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 | ){ int schemaMismatch = 0; sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int rc; /* Return code */ const char *zTab = 0; /* Name of current table */ int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ memset(&sApply, 0, sizeof(sApply)); rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); if( rc!=SQLITE_OK ) return rc; sqlite3_mutex_enter(sqlite3_db_mutex(db)); rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); | > > | 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 | ){ int schemaMismatch = 0; sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int rc; /* Return code */ const char *zTab = 0; /* Name of current table */ int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ assert( xConflict!=0 ); memset(&sApply, 0, sizeof(sApply)); rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); if( rc!=SQLITE_OK ) return rc; sqlite3_mutex_enter(sqlite3_db_mutex(db)); rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); |
︙ | ︙ | |||
3165 3166 3167 3168 3169 3170 3171 | } if( rc==SQLITE_OK ){ int nFk, notUsed; sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, ¬Used, 0); if( nFk!=0 ){ int res = SQLITE_CHANGESET_ABORT; | < | | | | < | 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 | } if( rc==SQLITE_OK ){ int nFk, notUsed; sqlite3_db_status(db, SQLITE_DBSTATUS_DEFERRED_FKS, &nFk, ¬Used, 0); if( nFk!=0 ){ int res = SQLITE_CHANGESET_ABORT; sqlite3_changeset_iter sIter; memset(&sIter, 0, sizeof(sIter)); sIter.nCol = nFk; res = xConflict(pCtx, SQLITE_CHANGESET_FOREIGN_KEY, &sIter); if( res!=SQLITE_CHANGESET_OMIT ){ rc = SQLITE_CONSTRAINT; } } } sqlite3_exec(db, "PRAGMA defer_foreign_keys = 0", 0, 0, 0); |
︙ | ︙ |
Changes to ext/session/sqlite3session.h.
︙ | ︙ | |||
730 731 732 733 734 735 736 737 738 739 740 741 742 743 | ** ** For each change for which there is a compatible table, an attempt is made ** to modify the table contents according to the UPDATE, INSERT or DELETE ** change. If a change cannot be applied cleanly, the conflict handler ** function passed as the fifth argument to sqlite3changeset_apply() may be ** invoked. A description of exactly when the conflict handler is invoked for ** each type of change is below. ** ** Each time the conflict handler function is invoked, it must return one ** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned ** if the second argument passed to the conflict handler is either ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler ** returns an illegal value, any changes already made are rolled back and | > > > > | 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | ** ** For each change for which there is a compatible table, an attempt is made ** to modify the table contents according to the UPDATE, INSERT or DELETE ** change. If a change cannot be applied cleanly, the conflict handler ** function passed as the fifth argument to sqlite3changeset_apply() may be ** invoked. A description of exactly when the conflict handler is invoked for ** each type of change is below. ** ** Unlike the xFilter argument, xConflict may not be passed NULL. The results ** of passing anything other than a valid function pointer as the xConflict ** argument are undefined. ** ** Each time the conflict handler function is invoked, it must return one ** of [SQLITE_CHANGESET_OMIT], [SQLITE_CHANGESET_ABORT] or ** [SQLITE_CHANGESET_REPLACE]. SQLITE_CHANGESET_REPLACE may only be returned ** if the second argument passed to the conflict handler is either ** SQLITE_CHANGESET_DATA or SQLITE_CHANGESET_CONFLICT. If the conflict-handler ** returns an illegal value, any changes already made are rolled back and |
︙ | ︙ |
Changes to ext/session/test_session.c.
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 | }else{ sqlite3_value *pVal; int rc = sqlite3changeset_old(pIter, -1, &pVal); assert( rc==SQLITE_RANGE ); rc = sqlite3changeset_old(pIter, nCol, &pVal); assert( rc==SQLITE_RANGE ); } /* End of testing block ***********************************************************************/ } if( TCL_OK!=Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL) ){ Tcl_BackgroundError(interp); }else{ | > > > > > > > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 | }else{ sqlite3_value *pVal; int rc = sqlite3changeset_old(pIter, -1, &pVal); assert( rc==SQLITE_RANGE ); rc = sqlite3changeset_old(pIter, nCol, &pVal); assert( rc==SQLITE_RANGE ); } if( eConf!=SQLITE_CHANGESET_FOREIGN_KEY ){ /* eConf!=FOREIGN_KEY is always true at this point. The condition is ** just there to make it clearer what is being tested. */ int nDummy; int rc = sqlite3changeset_fk_conflicts(pIter, &nDummy); assert( rc==SQLITE_MISUSE ); } /* End of testing block ***********************************************************************/ } if( TCL_OK!=Tcl_EvalObjEx(interp, pEval, TCL_EVAL_GLOBAL) ){ Tcl_BackgroundError(interp); }else{ |
︙ | ︙ | |||
435 436 437 438 439 440 441 442 443 444 445 446 447 448 | Tcl_GetIntFromObj(0, pRes, &ret); } } Tcl_DecrRefCount(pEval); return ret; } /* ** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT? */ static int test_sqlite3changeset_apply( void * clientData, Tcl_Interp *interp, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | Tcl_GetIntFromObj(0, pRes, &ret); } } Tcl_DecrRefCount(pEval); return ret; } /* ** The conflict handler used by sqlite3changeset_apply_replace_all(). ** This conflict handler calls sqlite3_value_text16() on all available ** sqlite3_value objects and then returns CHANGESET_REPLACE, or ** CHANGESET_OMIT if REPLACE is not applicable. This is used to test the ** effect of a malloc failure within an sqlite3_value_xxx() function ** invoked by a conflict-handler callback. */ static int replace_handler( void *pCtx, /* Pointer to TestConflictHandler structure */ int eConf, /* DATA, MISSING, CONFLICT, CONSTRAINT */ sqlite3_changeset_iter *pIter /* Handle describing change and conflict */ ){ int op; /* SQLITE_UPDATE, DELETE or INSERT */ const char *zTab; /* Name of table conflict is on */ int nCol; /* Number of columns in table zTab */ int i; int x = 0; sqlite3changeset_op(pIter, &zTab, &nCol, &op, 0); if( op!=SQLITE_INSERT ){ for(i=0; i<nCol; i++){ sqlite3_value *pVal; sqlite3changeset_old(pIter, i, &pVal); sqlite3_value_text16(pVal); x++; } } if( op!=SQLITE_DELETE ){ for(i=0; i<nCol; i++){ sqlite3_value *pVal; sqlite3changeset_new(pIter, i, &pVal); sqlite3_value_text16(pVal); x++; } } if( eConf==SQLITE_CHANGESET_DATA ){ return SQLITE_CHANGESET_REPLACE; } return SQLITE_CHANGESET_OMIT; } /* ** sqlite3changeset_apply DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT? */ static int test_sqlite3changeset_apply( void * clientData, Tcl_Interp *interp, |
︙ | ︙ | |||
477 478 479 480 481 482 483 484 485 486 487 488 489 490 | ); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc); } Tcl_ResetResult(interp); return TCL_OK; } /* ** sqlite3changeset_invert CHANGESET */ static int test_sqlite3changeset_invert( void * clientData, Tcl_Interp *interp, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 | ); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc); } Tcl_ResetResult(interp); return TCL_OK; } /* ** sqlite3changeset_apply_replace_all DB CHANGESET */ static int test_sqlite3changeset_apply_replace_all( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; /* Database handle */ Tcl_CmdInfo info; /* Database Tcl command (objv[1]) info */ int rc; /* Return code from changeset_invert() */ void *pChangeset; /* Buffer containing changeset */ int nChangeset; /* Size of buffer aChangeset in bytes */ if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB CHANGESET"); return TCL_ERROR; } if( 0==Tcl_GetCommandInfo(interp, Tcl_GetString(objv[1]), &info) ){ Tcl_AppendResult(interp, "no such handle: ", Tcl_GetString(objv[2]), 0); return TCL_ERROR; } db = *(sqlite3 **)info.objClientData; pChangeset = (void *)Tcl_GetByteArrayFromObj(objv[2], &nChangeset); rc = sqlite3changeset_apply(db, nChangeset, pChangeset, 0, replace_handler,0); if( rc!=SQLITE_OK ){ return test_session_error(interp, rc); } Tcl_ResetResult(interp); return TCL_OK; } /* ** sqlite3changeset_invert CHANGESET */ static int test_sqlite3changeset_invert( void * clientData, Tcl_Interp *interp, |
︙ | ︙ | |||
591 592 593 594 595 596 597 598 599 600 601 602 603 604 | Tcl_Obj *pOld; /* Vector of old.* values */ Tcl_Obj *pNew; /* Vector of new.* values */ int bIndirect; char *zPK; unsigned char *abPK; int i; sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); pVar = Tcl_NewObj(); Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj( op==SQLITE_INSERT ? "INSERT" : op==SQLITE_UPDATE ? "UPDATE" : "DELETE", -1 | > > > > > > > > | 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 | Tcl_Obj *pOld; /* Vector of old.* values */ Tcl_Obj *pNew; /* Vector of new.* values */ int bIndirect; char *zPK; unsigned char *abPK; int i; /* Test that _fk_conflicts() returns SQLITE_MISUSE if called on this ** iterator. */ int nDummy; if( SQLITE_MISUSE!=sqlite3changeset_fk_conflicts(pIter, &nDummy) ){ sqlite3changeset_finalize(pIter); return TCL_ERROR; } sqlite3changeset_op(pIter, &zTab, &nCol, &op, &bIndirect); pVar = Tcl_NewObj(); Tcl_ListObjAppendElement(0, pVar, Tcl_NewStringObj( op==SQLITE_INSERT ? "INSERT" : op==SQLITE_UPDATE ? "UPDATE" : "DELETE", -1 |
︙ | ︙ | |||
670 671 672 673 674 675 676 677 678 679 680 | ); Tcl_CreateObjCommand( interp, "sqlite3changeset_concat", test_sqlite3changeset_concat, 0, 0 ); Tcl_CreateObjCommand( interp, "sqlite3changeset_apply", test_sqlite3changeset_apply, 0, 0 ); return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ | > > > > | 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 | ); Tcl_CreateObjCommand( interp, "sqlite3changeset_concat", test_sqlite3changeset_concat, 0, 0 ); Tcl_CreateObjCommand( interp, "sqlite3changeset_apply", test_sqlite3changeset_apply, 0, 0 ); Tcl_CreateObjCommand( interp, "sqlite3changeset_apply_replace_all", test_sqlite3changeset_apply_replace_all, 0, 0 ); return TCL_OK; } #endif /* SQLITE_TEST && SQLITE_SESSION && SQLITE_PREUPDATE_HOOK */ |