]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add support for savepoints to fts5.
authordan <dan@noemail.net>
Wed, 6 Aug 2014 16:30:21 +0000 (16:30 +0000)
committerdan <dan@noemail.net>
Wed, 6 Aug 2014 16:30:21 +0000 (16:30 +0000)
FossilOrigin-Name: 3b19eba042bb2eeb1be60f8d58ebaa0a045d6a5c

ext/fts5/fts5.c
ext/fts5/fts5Int.h
ext/fts5/fts5_aux.c
ext/fts5/fts5_index.c
manifest
manifest.uuid
test/fts5ai.test [new file with mode: 0644]
test/permutations.test

index d2a5f0ce6e2d869b25b7380e63f04b08db73be8b..06d5b8c70b37dd3c1dea5d68ee8628f2abac0516 100644 (file)
 ** This is an SQLite module implementing full-text search.
 */
 
+
 #include "fts5Int.h"
 
+
 typedef struct Fts5Table Fts5Table;
 typedef struct Fts5Cursor Fts5Cursor;
 typedef struct Fts5Global Fts5Global;
 typedef struct Fts5Auxiliary Fts5Auxiliary;
 typedef struct Fts5Auxdata Fts5Auxdata;
 
+/*
+** NOTES ON TRANSACTIONS: 
+**
+** SQLite invokes the following virtual table methods as transactions are 
+** opened and closed by the user:
+**
+**     xBegin():    Start of a new transaction.
+**     xSync():     Initial part of two-phase commit.
+**     xCommit():   Final part of two-phase commit.
+**     xRollback(): Rollback the transaction.
+**
+** Anything that is required as part of a commit that may fail is performed
+** in the xSync() callback. Current versions of SQLite ignore any errors 
+** returned by xCommit().
+**
+** And as sub-transactions are opened/closed:
+**
+**     xSavepoint(int S):  Open savepoint S.
+**     xRelease(int S):    Commit and close savepoint S.
+**     xRollbackTo(int S): Rollback to start of savepoint S.
+**
+** During a write-transaction the fts5_index.c module may cache some data 
+** in-memory. It is flushed to disk whenever xSync(), xRelease() or
+** xSavepoint() is called. And discarded whenever xRollback() or xRollbackTo() 
+** is called.
+**
+** Additionally, if SQLITE_DEBUG is defined, an instance of the following
+** structure is used to record the current transaction state. This information
+** is not required, but it is used in the assert() statements executed by
+** function fts5CheckTransactionState() (see below).
+*/
+struct Fts5TransactionState {
+  int eState;                     /* 0==closed, 1==open, 2==synced */
+  int iSavepoint;                 /* Number of open savepoints (0 -> none) */
+};
+
 /*
 ** A single object of this type is allocated when the FTS5 module is 
 ** registered with a database handle. It is used to store pointers to
@@ -57,6 +95,9 @@ struct Fts5Table {
   Fts5Storage *pStorage;          /* Document store */
   Fts5Global *pGlobal;            /* Global (connection wide) data */
   Fts5Cursor *pSortCsr;           /* Sort data from this cursor */
+#ifdef SQLITE_DEBUG
+  struct Fts5TransactionState ts;
+#endif
 };
 
 struct Fts5MatchPhrase {
@@ -130,6 +171,64 @@ struct Fts5Auxdata {
   Fts5Auxdata *pNext;             /* Next object in linked list */
 };
 
+#ifdef SQLITE_DEBUG
+#define FTS5_BEGIN      1
+#define FTS5_SYNC       2
+#define FTS5_COMMIT     3
+#define FTS5_ROLLBACK   4
+#define FTS5_SAVEPOINT  5
+#define FTS5_RELEASE    6
+#define FTS5_ROLLBACKTO 7
+static void fts5CheckTransactionState(Fts5Table *p, int op, int iSavepoint){
+  switch( op ){
+    case FTS5_BEGIN:
+      assert( p->ts.eState==0 );
+      p->ts.eState = 1;
+      p->ts.iSavepoint = -1;
+      break;
+
+    case FTS5_SYNC:
+      assert( p->ts.eState==1 );
+      p->ts.eState = 2;
+      break;
+
+    case FTS5_COMMIT:
+      assert( p->ts.eState==2 );
+      p->ts.eState = 0;
+      break;
+
+    case FTS5_ROLLBACK:
+      assert( p->ts.eState==1 || p->ts.eState==2 );
+      p->ts.eState = 0;
+      break;
+
+    case FTS5_SAVEPOINT:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint>p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint;
+      break;
+      
+    case FTS5_RELEASE:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint<=p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint-1;
+      break;
+
+    case FTS5_ROLLBACKTO:
+      assert( p->ts.eState==1 );
+      assert( iSavepoint>=0 );
+      assert( iSavepoint<=p->ts.iSavepoint );
+      p->ts.iSavepoint = iSavepoint;
+      break;
+  }
+}
+#else
+# define fts5CheckTransactionState(x,y,z)
+#endif
+
+
 /*
 ** Close a virtual table handle opened by fts5InitVtab(). If the bDestroy
 ** argument is non-zero, attempt delete the shadow tables from teh database
@@ -222,6 +321,8 @@ static int fts5InitVtab(
   if( rc!=SQLITE_OK ){
     fts5FreeVtab(pTab, 0);
     pTab = 0;
+  }else if( bCreate ){
+    fts5CheckTransactionState(pTab, FTS5_BEGIN, 0);
   }
   *ppVTab = (sqlite3_vtab*)pTab;
   return rc;
@@ -793,6 +894,9 @@ static int fts5UpdateMethod(
   int eConflict;                  /* ON CONFLICT for this DML */
   int rc = SQLITE_OK;             /* Return code */
 
+  /* A transaction must be open when this is called. */
+  assert( pTab->ts.eState==1 );
+
   /* A delete specifies a single argument - the rowid of the row to remove.
   ** Update and insert operations pass:
   **
@@ -829,7 +933,8 @@ static int fts5UpdateMethod(
 static int fts5SyncMethod(sqlite3_vtab *pVtab){
   int rc;
   Fts5Table *pTab = (Fts5Table*)pVtab;
-  rc = sqlite3Fts5IndexSync(pTab->pIndex);
+  fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
+  rc = sqlite3Fts5IndexSync(pTab->pIndex, 1);
   return rc;
 }
 
@@ -837,6 +942,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
 ** Implementation of xBegin() method. 
 */
 static int fts5BeginMethod(sqlite3_vtab *pVtab){
+  fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0);
   return SQLITE_OK;
 }
 
@@ -846,6 +952,7 @@ static int fts5BeginMethod(sqlite3_vtab *pVtab){
 ** by fts5SyncMethod().
 */
 static int fts5CommitMethod(sqlite3_vtab *pVtab){
+  fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0);
   return SQLITE_OK;
 }
 
@@ -854,8 +961,9 @@ static int fts5CommitMethod(sqlite3_vtab *pVtab){
 ** hash-table. Any changes made to the database are reverted by SQLite.
 */
 static int fts5RollbackMethod(sqlite3_vtab *pVtab){
-  Fts5Table *pTab = (Fts5Table*)pVtab;
   int rc;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0);
   rc = sqlite3Fts5IndexRollback(pTab->pIndex);
   return rc;
 }
@@ -1243,8 +1351,9 @@ static int fts5RenameMethod(
 ** Flush the contents of the pending-terms table to disk.
 */
 static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
-  int rc = SQLITE_OK;
-  return rc;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+  return sqlite3Fts5IndexSync(pTab->pIndex, 0);
 }
 
 /*
@@ -1253,7 +1362,9 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
 ** This is a no-op.
 */
 static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
-  return SQLITE_OK;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+  return sqlite3Fts5IndexSync(pTab->pIndex, 0);
 }
 
 /*
@@ -1262,7 +1373,9 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
 ** Discard the contents of the pending terms table.
 */
 static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
-  return SQLITE_OK;
+  Fts5Table *pTab = (Fts5Table*)pVtab;
+  fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
+  return sqlite3Fts5IndexRollback(pTab->pIndex);
 }
 
 /*
index 07903abf834e7ae169b04c74c0c3be5d6a25f228..4ae110fd1964d06a33108c2816c3683828104837 100644 (file)
@@ -72,6 +72,7 @@ void sqlite3Fts5Dequote(char *z);
 **************************************************************************/
 
 /**************************************************************************
+** Interface to code in fts5_buffer.c.
 */
 
 /*
@@ -156,7 +157,6 @@ typedef struct Fts5IndexIter Fts5IndexIter;
 */
 #define FTS5INDEX_QUERY_PREFIX 0x0001       /* Prefix query */
 #define FTS5INDEX_QUERY_ASC    0x0002       /* Docs in ascending rowid order */
-#define FTS5INDEX_QUERY_MATCH  0x0004       /* Use the iMatch arg to Next() */
 
 /*
 ** Create/destroy an Fts5Index object.
@@ -230,22 +230,15 @@ void sqlite3Fts5IndexBeginWrite(
 
 /*
 ** Flush any data stored in the in-memory hash tables to the database.
-**
-** This is called whenever (a) the main transaction is committed or (b) a 
-** new sub-transaction is opened.
+** If the bCommit flag is true, also close any open blob handles.
 */
-void sqlite3Fts5IndexFlush(Fts5Index *p);
-
-int sqlite3Fts5IndexSync(Fts5Index *p);
+int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
 
 /*
 ** Discard any data stored in the in-memory hash tables. Do not write it
 ** to the database. Additionally, assume that the contents of the %_data
 ** table may have changed on disk. So any in-memory caches of %_data 
 ** records must be invalidated.
-**
-** This is called (a) whenever a main or sub-transaction is rolled back, 
-** and (b) whenever the read transaction is closed.
 */
 int sqlite3Fts5IndexRollback(Fts5Index *p);
 
@@ -256,9 +249,10 @@ int sqlite3Fts5IndexErrcode(Fts5Index*);
 void sqlite3Fts5IndexReset(Fts5Index*);
 
 /*
-** Get (bSet==0) or set (bSet!=0) the "averages" record.
+** Get or set the "averages" record.
 */
-void sqlite3Fts5IndexAverages(Fts5Index *p, int bSet, int nAvg, int *aAvg);
+int sqlite3Fts5IndexGetAverages(Fts5Index *p, Fts5Buffer *pBuf);
+int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
 
 /*
 ** Functions called by the storage module as part of integrity-check.
@@ -266,14 +260,23 @@ void sqlite3Fts5IndexAverages(Fts5Index *p, int bSet, int nAvg, int *aAvg);
 u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int);
 int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum);
 
-/* Called during startup to register a UDF with SQLite */
+/* 
+** Called during virtual module initialization to register UDF 
+** fts5_decode() with SQLite 
+*/
 int sqlite3Fts5IndexInit(sqlite3*);
 
+/*
+** Set the page size to use when writing. It doesn't matter if this
+** changes mid-transaction, or if inconsistent values are used by 
+** multiple clients.
+*/
 void sqlite3Fts5IndexPgsz(Fts5Index *p, int pgsz);
 
-int sqlite3Fts5IndexGetAverages(Fts5Index *p, Fts5Buffer *pBuf);
-int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int);
-
+/*
+** Return the total number of entries read from the %_data table by 
+** this connection since it was created.
+*/
 int sqlite3Fts5IndexReads(Fts5Index *p);
 
 /*
index d378bb67f41533abf22d6d8828c2739d05d3ee1f..85bad5c496ab23e2ea0a57e32ea5f97ce7950f92 100644 (file)
@@ -745,9 +745,10 @@ static void fts5TestFunction(
   memset(&s, 0, sizeof(Fts5Buffer));
   nCol = pApi->xColumnCount(pFts);
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, "columntotalsize ");
-  }
+  /*
+  ** xColumnTotalSize()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "columntotalsize ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "columntotalsize") ){
     if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "{");
     for(i=0; rc==SQLITE_OK && i<nCol; i++){
@@ -758,16 +759,19 @@ static void fts5TestFunction(
     if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "}");
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " columncount ");
-  }
+  /*
+  ** xColumnCount()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " columncount ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "columncount") ){
+    nCol = pApi->xColumnCount(pFts);
     sqlite3Fts5BufferAppendPrintf(&rc, &s, "%d", nCol);
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " columnsize ");
-  }
+  /*
+  ** xColumnSize()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " columnsize ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "columnsize") ){
     if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "{");
     for(i=0; rc==SQLITE_OK && i<nCol; i++){
@@ -778,9 +782,10 @@ static void fts5TestFunction(
     if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "}");
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " columntext ");
-  }
+  /*
+  ** xColumnText()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " columntext ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "columntext") ){
     for(i=0; rc==SQLITE_OK && i<nCol; i++){
       const char *z;
@@ -791,17 +796,19 @@ static void fts5TestFunction(
     }
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " phrasecount ");
-  }
+  /*
+  ** xPhraseCount()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " phrasecount ");
   nPhrase = pApi->xPhraseCount(pFts);
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "phrasecount") ){
     sqlite3Fts5BufferAppendPrintf(&rc, &s, "%d", nPhrase);
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " phrasesize ");
-  }
+  /*
+  ** xPhraseSize()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " phrasesize ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "phrasesize") ){
     if( nPhrase==1 ){
       int nSize = pApi->xPhraseSize(pFts, 0);
@@ -816,15 +823,15 @@ static void fts5TestFunction(
     }
   }
 
-  if( zReq==0 ){
-    sqlite3Fts5BufferAppendPrintf(&rc, &s, " poslist ");
-  }
+  /*
+  ** xPoslist()
+  */
+  if( zReq==0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " poslist ");
   if( 0==zReq || 0==sqlite3_stricmp(zReq, "poslist") ){
     int bParen = 0;
     Fts5Buffer s3;
     memset(&s3, 0, sizeof(s3));
 
-
     for(i=0; i<nPhrase; i++){
       Fts5Buffer s2;                  /* List of positions for phrase/column */
       int j = 0;
index 7d98ef72ffadd9be558dda018217882f28551ad2..1c6d175ab2a4498d2bc539ba9ba04b6cc409a558 100644 (file)
@@ -754,6 +754,16 @@ fprintf(stdout, "read: %s\n", buf.p);
 fflush(stdout);
 sqlite3_free(buf.p);
 #endif
+    if( p->pReader ){
+      /* This call may return SQLITE_ABORT if there has been a savepoint
+      ** rollback since it was last used. In this case a new blob handle
+      ** is required.  */
+      rc = sqlite3_blob_reopen(p->pReader, iRowid);
+      if( rc==SQLITE_ABORT ){
+        fts5CloseReader(p);
+        rc = SQLITE_OK;
+      }
+    }
 
     /* If the blob handle is not yet open, open and seek it. Otherwise, use
     ** the blob_reopen() API to reseek the existing blob handle.  */
@@ -762,8 +772,6 @@ sqlite3_free(buf.p);
       rc = sqlite3_blob_open(pConfig->db, 
           pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader
       );
-    }else{
-      rc = sqlite3_blob_reopen(p->pReader, iRowid);
     }
 
     if( rc ) fts5MissingData();
@@ -2482,6 +2490,25 @@ static Fts5PendingDoclist *fts5PendingList(Fts5Index *p, int iHash){
   return pList;
 }
 
+
+/*
+** Discard all data currently cached in the hash-tables.
+*/
+static void fts5IndexDiscardData(Fts5Index *p){
+  Fts5Config *pConfig = p->pConfig;
+  int i;
+  for(i=0; i<=pConfig->nPrefix; i++){
+    Fts3Hash *pHash = &p->aHash[i];
+    Fts3HashElem *pE;               /* Iterator variable */
+    for(pE=fts3HashFirst(pHash); pE; pE=fts3HashNext(pE)){
+      Fts5PendingDoclist *pDoclist = (Fts5PendingDoclist*)fts3HashData(pE);
+      fts5FreePendingDoclist(pDoclist);
+    }
+    fts3HashClear(pHash);
+  }
+  p->nPendingData = 0;
+}
+
 /*
 ** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares
 ** with buffer (nOld/pOld).
@@ -3145,21 +3172,10 @@ static void fts5FlushOneHash(Fts5Index *p, int iHash, int *pnLeaf){
   fts5StructureRelease(pStruct);
 }
 
-/*
-** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
-** to the document with rowid iRowid.
-*/
-void sqlite3Fts5IndexBeginWrite(Fts5Index *p, i64 iRowid){
-  if( iRowid<=p->iWriteRowid ){
-    sqlite3Fts5IndexFlush(p);
-  }
-  p->iWriteRowid = iRowid;
-}
-
 /*
 ** Flush any data stored in the in-memory hash tables to the database.
 */
-void sqlite3Fts5IndexFlush(Fts5Index *p){
+static void fts5IndexFlush(Fts5Index *p){
   Fts5Config *pConfig = p->pConfig;
   int i;                          /* Used to iterate through indexes */
   int nLeaf = 0;                  /* Number of leaves written */
@@ -3175,12 +3191,23 @@ void sqlite3Fts5IndexFlush(Fts5Index *p){
   p->nPendingData = 0;
 }
 
+/*
+** Indicate that all subsequent calls to sqlite3Fts5IndexWrite() pertain
+** to the document with rowid iRowid.
+*/
+void sqlite3Fts5IndexBeginWrite(Fts5Index *p, i64 iRowid){
+  if( iRowid<=p->iWriteRowid ){
+    fts5IndexFlush(p);
+  }
+  p->iWriteRowid = iRowid;
+}
+
 /*
 ** Commit data to disk.
 */
-int sqlite3Fts5IndexSync(Fts5Index *p){
-  sqlite3Fts5IndexFlush(p);
-  fts5CloseReader(p);
+int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
+  fts5IndexFlush(p);
+  if( bCommit ) fts5CloseReader(p);
   return p->rc;
 }
 
@@ -3192,6 +3219,7 @@ int sqlite3Fts5IndexSync(Fts5Index *p){
 */
 int sqlite3Fts5IndexRollback(Fts5Index *p){
   fts5CloseReader(p);
+  fts5IndexDiscardData(p);
   return SQLITE_OK;
 }
 
index 476c18f4f9f564a346edcec010abb1070ce07fb4..f539440020b9bb579ab84d5da33a924f25c18f3f 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Use\sdoclist\sindexes\sfor\sAND\squeries\sas\swell\sas\sphrases.
-D 2014-08-05T19:35:20.490
+C Add\ssupport\sfor\ssavepoints\sto\sfts5.
+D 2014-08-06T16:30:21.057
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -103,14 +103,14 @@ F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197
 F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c
 F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
 F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
-F ext/fts5/fts5.c 23f875e24ffa722107690d14b449141a25a2d697
+F ext/fts5/fts5.c 15e585ed0194f94a1da360808f29184f9d44554c
 F ext/fts5/fts5.h 8ace10d5b249a3baa983c79e7a1306d2a79cfd6a
-F ext/fts5/fts5Int.h aef50f3078e60707aeb2e4b2787d8c5eecdd02dc
-F ext/fts5/fts5_aux.c 366057c7186bc3615deb5ecc0ff61de50b6d2dbc
+F ext/fts5/fts5Int.h 410001da21bcc3d09b4290d4858352d0985ac7a6
+F ext/fts5/fts5_aux.c 31e581413ecab0962ce2b37468f9f658f36f4b0e
 F ext/fts5/fts5_buffer.c 248c61ac9fec001602efc72a45704f3b8d367c00
 F ext/fts5/fts5_config.c f4ebf143e141b8c77355e3b15aba81b7be51d710
 F ext/fts5/fts5_expr.c 7b8e380233176053841904a86006696ee8f6cd24
-F ext/fts5/fts5_index.c 40d9086948d6f1420a078bd9fb0b5372e54ec791
+F ext/fts5/fts5_index.c 6a9f851490562d8843edc4d54b27eb9472c62d68
 F ext/fts5/fts5_storage.c 2866e7e1de9dc851756c3a9c76b6e1d75e0facb7
 F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
@@ -603,6 +603,7 @@ F test/fts5ae.test cb37b3135a00d3afd5492ec534ecf654be5ff69e
 F test/fts5af.test 9ebe23aa3875896076952c7bc6e8308813a63c74
 F test/fts5ag.test 0747bf3bade16d5165810cf891f875933b28b420
 F test/fts5ah.test 009b993a9b7ebc43f84c10e53bd778b1dc8ffbe7
+F test/fts5ai.test 4dee71c23ddbcf2b0fc5d5586f241002b883c10e
 F test/fts5ea.test ff43b40f8879ba50b82def70f2ab67c195d1a1d4
 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
 F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
@@ -770,7 +771,7 @@ F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d
 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
 F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54
-F test/permutations.test 542edb965245565d06b9284e708f17bb93d70691
+F test/permutations.test 9875e7bacd0ab0cf78525e4b2d287840f284599b
 F test/pragma.test adb21a90875bc54a880fa939c4d7c46598905aa0
 F test/pragma2.test aea7b3d82c76034a2df2b38a13745172ddc0bc13
 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@@ -1199,7 +1200,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P d028ba6589f3122b635474c2683c0f93d5bc6c7c
-R df749c2987e3f7fa39a4c1c54f5a22e6
+P 5d38e6edc40ef188fbf96505073797036aa6783a
+R e4475b88a5ed55985c58ff03d579a6b6
 U dan
-Z 78f1e7641fc2b68987e4a3c99853c1c0
+Z 1737719499cd3c712a0cb60804b1642b
index 41e7ea9f1547d18ac13211a926d3e362792f4f3d..e8347f82056271bc564e1acbead3132dd343a98e 100644 (file)
@@ -1 +1 @@
-5d38e6edc40ef188fbf96505073797036aa6783a
\ No newline at end of file
+3b19eba042bb2eeb1be60f8d58ebaa0a045d6a5c
\ No newline at end of file
diff --git a/test/fts5ai.test b/test/fts5ai.test
new file mode 100644 (file)
index 0000000..705ca15
--- /dev/null
@@ -0,0 +1,56 @@
+# 2014 June 17
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#*************************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this script is testing the FTS5 module.
+#
+# Specifically, it tests transactions and savepoints
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix fts5ai
+
+# If SQLITE_ENABLE_FTS3 is defined, omit this file.
+ifcapable !fts3 {
+  finish_test
+  return
+}
+
+do_execsql_test 1.0 {
+  CREATE VIRTUAL TABLE t1 USING fts5(a);
+} {}
+
+do_execsql_test 1.1 {
+  BEGIN;
+    INSERT INTO t1 VALUES('a b c');
+    INSERT INTO t1 VALUES('d e f');
+    SAVEPOINT one;
+      INSERT INTO t1 VALUES('g h i');
+      SAVEPOINT two;
+        INSERT INTO t1 VALUES('j k l');
+    ROLLBACK TO one;
+      INSERT INTO t1 VALUES('m n o');
+        SAVEPOINT two;
+        INSERT INTO t1 VALUES('p q r');
+    RELEASE one;
+    SAVEPOINT one;
+      INSERT INTO t1 VALUES('s t u');
+    ROLLBACK TO one;
+  COMMIT;
+}
+
+do_execsql_test 1.2 {
+  INSERT INTO t1(t1) VALUES('integrity-check');
+}
+
+
+finish_test
+
index 41659ef8981b1ecdfa03b8fc5d9c1721841d27d0..550028ea32911736145a75518fd33949d9cd628f 100644 (file)
@@ -226,7 +226,7 @@ test_suite "fts5" -prefix "" -description {
   All FTS5 tests.
 } -files {
   fts5aa.test fts5ab.test fts5ac.test fts5ad.test fts5ae.test fts5ea.test
-  fts5af.test fts5ag.test fts5ah.test
+  fts5af.test fts5ag.test fts5ah.test fts5ai.test
 }
 
 test_suite "nofaultsim" -prefix "" -description {