Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix problems related to savepoint rollback and fts3. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | vtab-conflict |
Files: | files | file ages | folders |
SHA1: |
ff69f823f23e6fb6e8b2857c4576d9c0 |
User & Date: | dan 2011-04-27 12:08:04.566 |
Context
2011-04-27
| ||
16:02 | Add documentation for the newly introduced sqlite3_vtab_config() and on_conflict() API functions. Test that encountering an SQLITE_MISMATCH in fts3 does not corrupt the full text index. (check-in: abdd70ae04 user: dan tags: vtab-conflict) | |
12:08 | Fix problems related to savepoint rollback and fts3. (check-in: ff69f823f2 user: dan tags: vtab-conflict) | |
2011-04-26
| ||
19:21 | Extra tests for fts3. And fixes for conflict-handling related problems in fts3. (check-in: fb4a355871 user: dan tags: vtab-conflict) | |
Changes
Changes to src/sqliteInt.h.
︙ | ︙ | |||
867 868 869 870 871 872 873 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ | < < < | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 | #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int (*xProgress)(void *); /* The progress callback */ void *pProgressArg; /* Argument to the progress callback */ int nProgressOps; /* Number of opcodes for progress callback */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE Hash aModule; /* populated by sqlite3_create_module() */ VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ VTable **aVTrans; /* Virtual tables with open transactions */ int nVTrans; /* Allocated size of aVTrans */ VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ #endif FuncDefHash aFunc; /* Hash table of connection functions */ Hash aCollSeq; /* All collating sequences */ |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* ** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. */ #include "sqliteInt.h" #include "vdbeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* ** This is a copy of the first part of the SqliteDb structure in ** tclsqlite.c. We need it here so that the get_sqlite_pointer routine |
︙ | ︙ | |||
2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_readonly(pStmt); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_reset STMT ** ** Reset a statement handle. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > | 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 | } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_readonly(pStmt); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc)); return TCL_OK; } /* ** Usage: uses_stmt_journal STMT ** ** Return true if STMT uses a statement journal. */ static int uses_stmt_journal( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; int rc; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetStringFromObj(objv[0], 0), " STMT", 0); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_stmt_readonly(pStmt); Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal)); return TCL_OK; } /* ** Usage: sqlite3_reset STMT ** ** Reset a statement handle. */ |
︙ | ︙ | |||
5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 | { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, | > | 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 | { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 | */ sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - " "SQL statements in progress"); rc = SQLITE_BUSY; }else{ nName = sqlite3Strlen30(zName); /* Create a new savepoint structure. */ pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1); if( pNew ){ pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, zName, nName+1); /* If there is no open transaction, then mark this as a special | > > > > > > > > | 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 | */ sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - " "SQL statements in progress"); rc = SQLITE_BUSY; }else{ nName = sqlite3Strlen30(zName); /* This call is Ok even if this savepoint is actually a transaction ** savepoint (and therefore should not prompt xSavepoint()) callbacks. ** If this is a transaction savepoint being opened, it is guaranteed ** that the db->aVTrans[] array is empty. */ assert( db->autoCommit==0 || db->nVTrans==0 ); rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); if( rc!=SQLITE_OK ) goto abort_due_to_error; /* Create a new savepoint structure. */ pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1); if( pNew ){ pNew->zName = (char *)&pNew[1]; memcpy(pNew->zName, zName, nName+1); /* If there is no open transaction, then mark this as a special |
︙ | ︙ | |||
2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 | sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ db->nDeferredCons = pSavepoint->nDeferredCons; } } } break; } /* Opcode: AutoCommit P1 P2 * * * | > > > > > | 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 | sqlite3DbFree(db, pSavepoint); if( !isTransaction ){ db->nSavepoint--; } }else{ db->nDeferredCons = pSavepoint->nDeferredCons; } if( !isTransaction ){ rc = sqlite3VtabSavepoint(db, p1, iSavepoint); if( rc!=SQLITE_OK ) goto abort_due_to_error; } } } break; } /* Opcode: AutoCommit P1 P2 * * * |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
652 653 654 655 656 657 658 | Parse *pParse; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; sqlite3_mutex_enter(db->mutex); | | < | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 | Parse *pParse; int rc = SQLITE_OK; Table *pTab; char *zErr = 0; sqlite3_mutex_enter(db->mutex); if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ sqlite3Error(db, SQLITE_MISUSE, 0); sqlite3_mutex_leave(db->mutex); return SQLITE_MISUSE_BKPT; } assert( (pTab->tabFlags & TF_Virtual)!=0 ); pParse = sqlite3StackAllocZero(db, sizeof(*pParse)); |
︙ | ︙ | |||
848 849 850 851 852 853 854 855 | if( rc==SQLITE_OK ){ rc = addToVTrans(db, pVTab); } } return rc; } int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ | > > > > > > > > > > > > > > > < | > < | > | | | > > | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 | if( rc==SQLITE_OK ){ rc = addToVTrans(db, pVTab); } } return rc; } /* ** Invoke either the xSavepoint, xRollbackTo or xRelease method of all ** virtual tables that currently have an open transaction. Pass iSavepoint ** as the second argument to the virtual table method invoked. ** ** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is ** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is ** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with ** an open transaction is invoked. ** ** If any virtual table method returns an error code other than SQLITE_OK, ** processing is abandoned and the error returned to the caller of this ** function immediately. If all calls to virtual table methods are successful, ** SQLITE_OK is returned. */ int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); if( db->aVTrans ){ int i; for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; if( pMod->iVersion>=1 ){ int (*xMethod)(sqlite3_vtab *, int); switch( op ){ case SAVEPOINT_BEGIN: xMethod = pMod->xSavepoint; break; case SAVEPOINT_ROLLBACK: xMethod = pMod->xRollbackTo; break; default: xMethod = pMod->xRelease; break; } if( xMethod ) rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint); } } } return rc; } /* ** The first parameter (pDef) is a function implementation. The |
︙ | ︙ |
Changes to test/fts3conf.test.
︙ | ︙ | |||
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | DROP TABLE temp.fts3check2; DROP TABLE temp.fts3check3; } uplevel [list do_test $tn [list set {} $m1] $m2] } do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); INSERT INTO t1(rowid, x) VALUES(2, 'e f g h'); CREATE TABLE source(a, b); INSERT INTO source VALUES(4, 'z'); INSERT INTO source VALUES(2, 'y'); } db_save_and_close set T1 "INTO t1(rowid, x) VALUES(1, 'x')" set T2 "INTO t1(rowid, x) SELECT * FROM source" set T3 "t1 SET docid = 2 WHERE docid = 1" set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2" | > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | > > > > > > > > > > > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | DROP TABLE temp.fts3check2; DROP TABLE temp.fts3check3; } uplevel [list do_test $tn [list set {} $m1] $m2] } proc sql_uses_stmt {db sql} { set stmt [sqlite3_prepare db $sql -1 dummy] set uses [uses_stmt_journal $stmt] sqlite3_finalize $stmt return $uses } do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); INSERT INTO t1(rowid, x) VALUES(2, 'e f g h'); CREATE TABLE source(a, b); INSERT INTO source VALUES(4, 'z'); INSERT INTO source VALUES(2, 'y'); } db_save_and_close set T1 "INTO t1(rowid, x) VALUES(1, 'x')" set T2 "INTO t1(rowid, x) SELECT * FROM source" set T3 "t1 SET docid = 2 WHERE docid = 1" set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2" foreach {tn sql uses constraint data} [subst { 1 "INSERT OR ROLLBACK $T1" 0 1 {{a b c d} {e f g h}} 2 "INSERT OR ABORT $T1" 0 1 {{a b c d} {e f g h} {i j k l}} 3 "INSERT OR FAIL $T1" 0 1 {{a b c d} {e f g h} {i j k l}} 4 "INSERT OR IGNORE $T1" 0 0 {{a b c d} {e f g h} {i j k l}} 5 "INSERT OR REPLACE $T1" 0 0 {x {e f g h} {i j k l}} 6 "INSERT OR ROLLBACK $T2" 1 1 {{a b c d} {e f g h}} 7 "INSERT OR ABORT $T2" 1 1 {{a b c d} {e f g h} {i j k l}} 8 "INSERT OR FAIL $T2" 1 1 {{a b c d} {e f g h} {i j k l} z} 9 "INSERT OR IGNORE $T2" 1 0 {{a b c d} {e f g h} {i j k l} z} 10 "INSERT OR REPLACE $T2" 1 0 {{a b c d} y {i j k l} z} 11 "UPDATE OR ROLLBACK $T3" 1 1 {{a b c d} {e f g h}} 12 "UPDATE OR ABORT $T3" 1 1 {{a b c d} {e f g h} {i j k l}} 13 "UPDATE OR FAIL $T3" 1 1 {{a b c d} {e f g h} {i j k l}} 14 "UPDATE OR IGNORE $T3" 1 0 {{a b c d} {e f g h} {i j k l}} 15 "UPDATE OR REPLACE $T3" 1 0 {{a b c d} {i j k l}} 16 "UPDATE OR ROLLBACK $T4" 1 1 {{a b c d} {e f g h}} 17 "UPDATE OR ABORT $T4" 1 1 {{a b c d} {e f g h} {i j k l}} 18 "UPDATE OR FAIL $T4" 1 1 {{e f g h} {i j k l} {a b c d}} 19 "UPDATE OR IGNORE $T4" 1 0 {{e f g h} {i j k l} {a b c d}} 20 "UPDATE OR REPLACE $T4" 1 0 {{e f g h} {a b c d}} }] { db_restore_and_reopen execsql { BEGIN; INSERT INTO t1(rowid, x) VALUES(3, 'i j k l'); } set R(0) {0 {}} set R(1) {1 {constraint failed}} do_catchsql_test 1.$tn.1 $sql $R($constraint) do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data] catchsql COMMIT fts3_integrity 1.$tn.3 db t1 do_test 1.$tn.4 [list sql_uses_stmt db $sql] $uses } do_execsql_test 2.1.1 { DELETE FROM t1; BEGIN; INSERT INTO t1 VALUES('a b c'); SAVEPOINT a; INSERT INTO t1 VALUES('x y z'); ROLLBACK TO a; COMMIT; } fts3_integrity 2.1.2 db t1 finish_test |