/ Check-in [ff69f823]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix problems related to savepoint rollback and fts3.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | vtab-conflict
Files: files | file ages | folders
SHA1: ff69f823f23e6fb6e8b2857c4576d9c0732d9572
User & Date: dan 2011-04-27 12:08:04
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: abdd70ae user: dan tags: vtab-conflict
12:08
Fix problems related to savepoint rollback and fts3. check-in: ff69f823 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: fb4a3558 user: dan tags: vtab-conflict
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/sqliteInt.h.

   867    867   #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
   868    868     int (*xProgress)(void *);     /* The progress callback */
   869    869     void *pProgressArg;           /* Argument to the progress callback */
   870    870     int nProgressOps;             /* Number of opcodes for progress callback */
   871    871   #endif
   872    872   #ifndef SQLITE_OMIT_VIRTUALTABLE
   873    873     Hash aModule;                 /* populated by sqlite3_create_module() */
   874         -#if 0
   875         -  Table *pVTab;                 /* vtab with active Connect/Create method */
   876         -#endif
   877    874     VtabCtx *pVtabCtx;            /* Context for active vtab connect/create */
   878    875     VTable **aVTrans;             /* Virtual tables with open transactions */
   879    876     int nVTrans;                  /* Allocated size of aVTrans */
   880    877     VTable *pDisconnect;    /* Disconnect these in next sqlite3_prepare() */
   881    878   #endif
   882    879     FuncDefHash aFunc;            /* Hash table of connection functions */
   883    880     Hash aCollSeq;                /* All collating sequences */

Changes to src/test1.c.

    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing all sorts of SQLite interfaces.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   */
    16     16   #include "sqliteInt.h"
           17  +#include "vdbeInt.h"
    17     18   #include "tcl.h"
    18     19   #include <stdlib.h>
    19     20   #include <string.h>
    20     21   
    21     22   /*
    22     23   ** This is a copy of the first part of the SqliteDb structure in 
    23     24   ** tclsqlite.c.  We need it here so that the get_sqlite_pointer routine
................................................................................
  2321   2322     }
  2322   2323   
  2323   2324     if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  2324   2325     rc = sqlite3_stmt_readonly(pStmt);
  2325   2326     Tcl_SetObjResult(interp, Tcl_NewBooleanObj(rc));
  2326   2327     return TCL_OK;
  2327   2328   }
         2329  +
         2330  +/*
         2331  +** Usage:  uses_stmt_journal  STMT
         2332  +**
         2333  +** Return true if STMT uses a statement journal.
         2334  +*/
         2335  +static int uses_stmt_journal(
         2336  +  void * clientData,
         2337  +  Tcl_Interp *interp,
         2338  +  int objc,
         2339  +  Tcl_Obj *CONST objv[]
         2340  +){
         2341  +  sqlite3_stmt *pStmt;
         2342  +  int rc;
         2343  +
         2344  +  if( objc!=2 ){
         2345  +    Tcl_AppendResult(interp, "wrong # args: should be \"",
         2346  +        Tcl_GetStringFromObj(objv[0], 0), " STMT", 0);
         2347  +    return TCL_ERROR;
         2348  +  }
         2349  +
         2350  +  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
         2351  +  rc = sqlite3_stmt_readonly(pStmt);
         2352  +  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(((Vdbe *)pStmt)->usesStmtJournal));
         2353  +  return TCL_OK;
         2354  +}
  2328   2355   
  2329   2356   
  2330   2357   /*
  2331   2358   ** Usage:  sqlite3_reset  STMT 
  2332   2359   **
  2333   2360   ** Reset a statement handle.
  2334   2361   */
................................................................................
  5579   5606        { "sqlite3_expired",               test_expired       ,0 },
  5580   5607        { "sqlite3_transfer_bindings",     test_transfer_bind ,0 },
  5581   5608        { "sqlite3_changes",               test_changes       ,0 },
  5582   5609        { "sqlite3_step",                  test_step          ,0 },
  5583   5610        { "sqlite3_sql",                   test_sql           ,0 },
  5584   5611        { "sqlite3_next_stmt",             test_next_stmt     ,0 },
  5585   5612        { "sqlite3_stmt_readonly",         test_stmt_readonly ,0 },
         5613  +     { "uses_stmt_journal",             uses_stmt_journal ,0 },
  5586   5614   
  5587   5615        { "sqlite3_release_memory",        test_release_memory,     0},
  5588   5616        { "sqlite3_soft_heap_limit",       test_soft_heap_limit,    0},
  5589   5617        { "sqlite3_thread_cleanup",        test_thread_cleanup,     0},
  5590   5618        { "sqlite3_pager_refcounts",       test_pager_refcounts,    0},
  5591   5619   
  5592   5620        { "sqlite3_load_extension",        test_load_extension,     0},

Changes to src/vdbe.c.

  2576   2576         */
  2577   2577         sqlite3SetString(&p->zErrMsg, db, "cannot open savepoint - "
  2578   2578           "SQL statements in progress");
  2579   2579         rc = SQLITE_BUSY;
  2580   2580       }else{
  2581   2581         nName = sqlite3Strlen30(zName);
  2582   2582   
         2583  +      /* This call is Ok even if this savepoint is actually a transaction
         2584  +      ** savepoint (and therefore should not prompt xSavepoint()) callbacks.
         2585  +      ** If this is a transaction savepoint being opened, it is guaranteed
         2586  +      ** that the db->aVTrans[] array is empty.  */
         2587  +      assert( db->autoCommit==0 || db->nVTrans==0 );
         2588  +      rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement);
         2589  +      if( rc!=SQLITE_OK ) goto abort_due_to_error;
         2590  +
  2583   2591         /* Create a new savepoint structure. */
  2584   2592         pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+nName+1);
  2585   2593         if( pNew ){
  2586   2594           pNew->zName = (char *)&pNew[1];
  2587   2595           memcpy(pNew->zName, zName, nName+1);
  2588   2596       
  2589   2597           /* If there is no open transaction, then mark this as a special
................................................................................
  2682   2690           sqlite3DbFree(db, pSavepoint);
  2683   2691           if( !isTransaction ){
  2684   2692             db->nSavepoint--;
  2685   2693           }
  2686   2694         }else{
  2687   2695           db->nDeferredCons = pSavepoint->nDeferredCons;
  2688   2696         }
         2697  +
         2698  +      if( !isTransaction ){
         2699  +        rc = sqlite3VtabSavepoint(db, p1, iSavepoint);
         2700  +        if( rc!=SQLITE_OK ) goto abort_due_to_error;
         2701  +      }
  2689   2702       }
  2690   2703     }
  2691   2704   
  2692   2705     break;
  2693   2706   }
  2694   2707   
  2695   2708   /* Opcode: AutoCommit P1 P2 * * *

Changes to src/vtab.c.

   652    652     Parse *pParse;
   653    653   
   654    654     int rc = SQLITE_OK;
   655    655     Table *pTab;
   656    656     char *zErr = 0;
   657    657   
   658    658     sqlite3_mutex_enter(db->mutex);
   659         -  pTab = db->pVtabCtx->pTab;
   660         -  if( !pTab ){
          659  +  if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){
   661    660       sqlite3Error(db, SQLITE_MISUSE, 0);
   662    661       sqlite3_mutex_leave(db->mutex);
   663    662       return SQLITE_MISUSE_BKPT;
   664    663     }
   665    664     assert( (pTab->tabFlags & TF_Virtual)!=0 );
   666    665   
   667    666     pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
................................................................................
   848    847       if( rc==SQLITE_OK ){
   849    848         rc = addToVTrans(db, pVTab);
   850    849       }
   851    850     }
   852    851     return rc;
   853    852   }
   854    853   
          854  +/*
          855  +** Invoke either the xSavepoint, xRollbackTo or xRelease method of all
          856  +** virtual tables that currently have an open transaction. Pass iSavepoint
          857  +** as the second argument to the virtual table method invoked.
          858  +**
          859  +** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is
          860  +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is 
          861  +** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with
          862  +** an open transaction is invoked.
          863  +**
          864  +** If any virtual table method returns an error code other than SQLITE_OK, 
          865  +** processing is abandoned and the error returned to the caller of this
          866  +** function immediately. If all calls to virtual table methods are successful,
          867  +** SQLITE_OK is returned.
          868  +*/
   855    869   int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
   856         -  int i;
   857    870     int rc = SQLITE_OK;
   858    871   
   859    872     assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN );
   860         -
   861         -  for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
   862         -    sqlite3_vtab *pVtab = db->aVTrans[i]->pVtab;
   863         -    sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule;
   864         -    if( pMod->iVersion>=1 ){
   865         -      switch( op ){
   866         -        case SAVEPOINT_BEGIN:
   867         -          rc = pMod->xSavepoint(pVtab, iSavepoint);
   868         -          break;
   869         -        case SAVEPOINT_ROLLBACK:
   870         -          rc = pMod->xRollbackTo(pVtab, iSavepoint);
   871         -          break;
   872         -        default:
   873         -          rc = pMod->xRelease(pVtab, iSavepoint);
   874         -          break;
          873  +  if( db->aVTrans ){
          874  +    int i;
          875  +    for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){
          876  +      const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule;
          877  +      if( pMod->iVersion>=1 ){
          878  +        int (*xMethod)(sqlite3_vtab *, int);
          879  +        switch( op ){
          880  +          case SAVEPOINT_BEGIN:
          881  +            xMethod = pMod->xSavepoint;
          882  +            break;
          883  +          case SAVEPOINT_ROLLBACK:
          884  +            xMethod = pMod->xRollbackTo;
          885  +            break;
          886  +          default:
          887  +            xMethod = pMod->xRelease;
          888  +            break;
          889  +        }
          890  +        if( xMethod ) rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint);
   875    891         }
   876    892       }
   877    893     }
   878    894     return rc;
   879    895   }
   880    896   
   881    897   /*

Changes to test/fts3conf.test.

    52     52       DROP TABLE temp.fts3check2;
    53     53       DROP TABLE temp.fts3check3;
    54     54     }
    55     55     
    56     56     uplevel [list do_test $tn [list set {} $m1] $m2]
    57     57   }
    58     58   
           59  +proc sql_uses_stmt {db sql} {
           60  +  set stmt [sqlite3_prepare db $sql -1 dummy]
           61  +  set uses [uses_stmt_journal $stmt]
           62  +  sqlite3_finalize $stmt
           63  +  return $uses
           64  +}
           65  +
           66  +
    59     67   
    60     68   
    61     69   do_execsql_test 1.0.1 {
    62     70     CREATE VIRTUAL TABLE t1 USING fts3(x);
    63     71     INSERT INTO t1(rowid, x) VALUES(1, 'a b c d');
    64     72     INSERT INTO t1(rowid, x) VALUES(2, 'e f g h');
    65     73   
................................................................................
    71     79   
    72     80   set T1 "INTO t1(rowid, x) VALUES(1, 'x')"
    73     81   set T2 "INTO t1(rowid, x) SELECT * FROM source"
    74     82   
    75     83   set T3 "t1 SET docid = 2 WHERE docid = 1"
    76     84   set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2"
    77     85   
    78         -foreach {tn sql constraint data} [subst {
    79         -  1    "INSERT OR ROLLBACK $T1"   1 {{a b c d} {e f g h}}
    80         -  2    "INSERT OR ABORT    $T1"   1 {{a b c d} {e f g h} {i j k l}}
    81         -  3    "INSERT OR FAIL     $T1"   1 {{a b c d} {e f g h} {i j k l}}
    82         -  4    "INSERT OR IGNORE   $T1"   0 {{a b c d} {e f g h} {i j k l}}
    83         -  5    "INSERT OR REPLACE  $T1"   0 {x {e f g h} {i j k l}}
           86  +foreach {tn sql uses constraint data} [subst {
           87  +  1    "INSERT OR ROLLBACK $T1"   0 1 {{a b c d} {e f g h}}
           88  +  2    "INSERT OR ABORT    $T1"   0 1 {{a b c d} {e f g h} {i j k l}}
           89  +  3    "INSERT OR FAIL     $T1"   0 1 {{a b c d} {e f g h} {i j k l}}
           90  +  4    "INSERT OR IGNORE   $T1"   0 0 {{a b c d} {e f g h} {i j k l}}
           91  +  5    "INSERT OR REPLACE  $T1"   0 0 {x {e f g h} {i j k l}}
           92  +
           93  +  6    "INSERT OR ROLLBACK $T2"   1 1 {{a b c d} {e f g h}}
           94  +  7    "INSERT OR ABORT    $T2"   1 1 {{a b c d} {e f g h} {i j k l}}
           95  +  8    "INSERT OR FAIL     $T2"   1 1 {{a b c d} {e f g h} {i j k l} z}
           96  +  9    "INSERT OR IGNORE   $T2"   1 0 {{a b c d} {e f g h} {i j k l} z}
           97  +  10   "INSERT OR REPLACE  $T2"   1 0 {{a b c d} y {i j k l} z}
    84     98   
    85         -  6    "INSERT OR ROLLBACK $T2"   1 {{a b c d} {e f g h}}
    86         -  7    "INSERT OR ABORT    $T2"   1 {{a b c d} {e f g h} {i j k l}}
    87         -  8    "INSERT OR FAIL     $T2"   1 {{a b c d} {e f g h} {i j k l} z}
    88         -  9    "INSERT OR IGNORE   $T2"   0 {{a b c d} {e f g h} {i j k l} z}
    89         -  10   "INSERT OR REPLACE  $T2"   0 {{a b c d} y {i j k l} z}
           99  +  11   "UPDATE OR ROLLBACK $T3"   1 1 {{a b c d} {e f g h}}
          100  +  12   "UPDATE OR ABORT    $T3"   1 1 {{a b c d} {e f g h} {i j k l}}
          101  +  13   "UPDATE OR FAIL     $T3"   1 1 {{a b c d} {e f g h} {i j k l}}
          102  +  14   "UPDATE OR IGNORE   $T3"   1 0 {{a b c d} {e f g h} {i j k l}}
          103  +  15   "UPDATE OR REPLACE  $T3"   1 0 {{a b c d} {i j k l}}
    90    104   
    91         -  11   "UPDATE OR ROLLBACK $T3"   1 {{a b c d} {e f g h}}
    92         -  12   "UPDATE OR ABORT    $T3"   1 {{a b c d} {e f g h} {i j k l}}
    93         -  13   "UPDATE OR FAIL     $T3"   1 {{a b c d} {e f g h} {i j k l}}
    94         -  14   "UPDATE OR IGNORE   $T3"   0 {{a b c d} {e f g h} {i j k l}}
    95         -  15   "UPDATE OR REPLACE  $T3"   0 {{a b c d} {i j k l}}
    96         -
    97         -  16   "UPDATE OR ROLLBACK $T4"   1 {{a b c d} {e f g h}}
    98         -  17   "UPDATE OR ABORT    $T4"   1 {{a b c d} {e f g h} {i j k l}}
    99         -  18   "UPDATE OR FAIL     $T4"   1 {{e f g h} {i j k l} {a b c d}}
   100         -  19   "UPDATE OR IGNORE   $T4"   0 {{e f g h} {i j k l} {a b c d}}
   101         -  20   "UPDATE OR REPLACE  $T4"   0 {{e f g h} {a b c d}}
          105  +  16   "UPDATE OR ROLLBACK $T4"   1 1 {{a b c d} {e f g h}}
          106  +  17   "UPDATE OR ABORT    $T4"   1 1 {{a b c d} {e f g h} {i j k l}}
          107  +  18   "UPDATE OR FAIL     $T4"   1 1 {{e f g h} {i j k l} {a b c d}}
          108  +  19   "UPDATE OR IGNORE   $T4"   1 0 {{e f g h} {i j k l} {a b c d}}
          109  +  20   "UPDATE OR REPLACE  $T4"   1 0 {{e f g h} {a b c d}}
   102    110   }] {
   103    111     db_restore_and_reopen
   104    112     execsql { 
   105    113       BEGIN;
   106    114         INSERT INTO t1(rowid, x) VALUES(3, 'i j k l');
   107    115     }
   108    116     set R(0) {0 {}}
   109    117     set R(1) {1 {constraint failed}}
   110    118     do_catchsql_test 1.$tn.1 $sql $R($constraint)
   111    119     do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data]
   112    120     catchsql COMMIT
   113    121   
   114    122     fts3_integrity 1.$tn.3 db t1
          123  +
          124  +  do_test 1.$tn.4 [list sql_uses_stmt db $sql] $uses
          125  +}
          126  +
          127  +do_execsql_test 2.1.1 {
          128  +  DELETE FROM t1;
          129  +  BEGIN;
          130  +    INSERT INTO t1 VALUES('a b c');
          131  +    SAVEPOINT a;
          132  +      INSERT INTO t1 VALUES('x y z');
          133  +    ROLLBACK TO a;
          134  +  COMMIT;
   115    135   }
          136  +fts3_integrity 2.1.2 db t1
   116    137   
   117    138   
   118    139   finish_test