Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for savepoints to fts5. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | fts5 |
Files: | files | file ages | folders |
SHA1: |
3b19eba042bb2eeb1be60f8d58ebaa0a |
User & Date: | dan 2014-08-06 16:30:21.057 |
Context
2014-08-06
| ||
20:04 | Avoid writing delete markers to the oldest segment in an FTS index. (check-in: 1baeb1cee6 user: dan tags: fts5) | |
16:30 | Add support for savepoints to fts5. (check-in: 3b19eba042 user: dan tags: fts5) | |
2014-08-05
| ||
19:35 | Use doclist indexes for AND queries as well as phrases. (check-in: 5d38e6edc4 user: dan tags: fts5) | |
Changes
Changes to ext/fts5/fts5.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** 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; /* ** 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 ** all registered FTS5 extensions - tokenizers and auxiliary functions. */ struct Fts5Global { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** 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 ** all registered FTS5 extensions - tokenizers and auxiliary functions. */ struct Fts5Global { |
︙ | ︙ | |||
53 54 55 56 57 58 59 60 61 62 63 64 65 66 | struct Fts5Table { sqlite3_vtab base; /* Base class used by SQLite core */ Fts5Config *pConfig; /* Virtual table configuration */ Fts5Index *pIndex; /* Full-text index */ Fts5Storage *pStorage; /* Document store */ Fts5Global *pGlobal; /* Global (connection wide) data */ Fts5Cursor *pSortCsr; /* Sort data from this cursor */ }; struct Fts5MatchPhrase { Fts5Buffer *pPoslist; /* Pointer to current poslist */ int nTerm; /* Size of phrase in terms */ }; | > > > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | struct Fts5Table { sqlite3_vtab base; /* Base class used by SQLite core */ Fts5Config *pConfig; /* Virtual table configuration */ Fts5Index *pIndex; /* Full-text index */ 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 { Fts5Buffer *pPoslist; /* Pointer to current poslist */ int nTerm; /* Size of phrase in terms */ }; |
︙ | ︙ | |||
125 126 127 128 129 130 131 132 133 134 135 136 137 138 | struct Fts5Auxdata { Fts5Auxiliary *pAux; /* Extension to which this belongs */ void *pPtr; /* Pointer value */ void(*xDelete)(void*); /* Destructor */ Fts5Auxdata *pNext; /* Next object in linked list */ }; /* ** Close a virtual table handle opened by fts5InitVtab(). If the bDestroy ** argument is non-zero, attempt delete the shadow tables from teh database */ static int fts5FreeVtab(Fts5Table *pTab, int bDestroy){ int rc = SQLITE_OK; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | struct Fts5Auxdata { Fts5Auxiliary *pAux; /* Extension to which this belongs */ void *pPtr; /* Pointer value */ void(*xDelete)(void*); /* Destructor */ 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 */ static int fts5FreeVtab(Fts5Table *pTab, int bDestroy){ int rc = SQLITE_OK; |
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigDeclareVtab(pConfig); } if( rc!=SQLITE_OK ){ fts5FreeVtab(pTab, 0); pTab = 0; } *ppVTab = (sqlite3_vtab*)pTab; return rc; } /* ** The xConnect() and xCreate() methods for the virtual table. All the | > > | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | if( rc==SQLITE_OK ){ rc = sqlite3Fts5ConfigDeclareVtab(pConfig); } if( rc!=SQLITE_OK ){ fts5FreeVtab(pTab, 0); pTab = 0; }else if( bCreate ){ fts5CheckTransactionState(pTab, FTS5_BEGIN, 0); } *ppVTab = (sqlite3_vtab*)pTab; return rc; } /* ** The xConnect() and xCreate() methods for the virtual table. All the |
︙ | ︙ | |||
788 789 790 791 792 793 794 795 796 797 798 799 800 801 | sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts5Table *pTab = (Fts5Table*)pVtab; Fts5Config *pConfig = pTab->pConfig; int eType0; /* value_type() of apVal[0] */ int eConflict; /* ON CONFLICT for this DML */ int rc = SQLITE_OK; /* Return code */ /* A delete specifies a single argument - the rowid of the row to remove. ** Update and insert operations pass: ** ** 1. The "old" rowid, or NULL. ** 2. The "new" rowid. ** 3. Values for each of the nCol matchable columns. | > > > | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 | sqlite_int64 *pRowid /* OUT: The affected (or effected) rowid */ ){ Fts5Table *pTab = (Fts5Table*)pVtab; Fts5Config *pConfig = pTab->pConfig; int eType0; /* value_type() of apVal[0] */ 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: ** ** 1. The "old" rowid, or NULL. ** 2. The "new" rowid. ** 3. Values for each of the nCol matchable columns. |
︙ | ︙ | |||
825 826 827 828 829 830 831 | /* ** Implementation of xSync() method. */ static int fts5SyncMethod(sqlite3_vtab *pVtab){ int rc; Fts5Table *pTab = (Fts5Table*)pVtab; | > | > > < > > | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 | /* ** Implementation of xSync() method. */ static int fts5SyncMethod(sqlite3_vtab *pVtab){ int rc; Fts5Table *pTab = (Fts5Table*)pVtab; fts5CheckTransactionState(pTab, FTS5_SYNC, 0); rc = sqlite3Fts5IndexSync(pTab->pIndex, 1); return rc; } /* ** Implementation of xBegin() method. */ static int fts5BeginMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_BEGIN, 0); return SQLITE_OK; } /* ** Implementation of xCommit() method. This is a no-op. The contents of ** the pending-terms hash-table have already been flushed into the database ** by fts5SyncMethod(). */ static int fts5CommitMethod(sqlite3_vtab *pVtab){ fts5CheckTransactionState((Fts5Table*)pVtab, FTS5_COMMIT, 0); return SQLITE_OK; } /* ** Implementation of xRollback(). Discard the contents of the pending-terms ** hash-table. Any changes made to the database are reverted by SQLite. */ static int fts5RollbackMethod(sqlite3_vtab *pVtab){ int rc; Fts5Table *pTab = (Fts5Table*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACK, 0); rc = sqlite3Fts5IndexRollback(pTab->pIndex); return rc; } static void *fts5ApiUserData(Fts5Context *pCtx){ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; return pCsr->pAux->pUserData; |
︙ | ︙ | |||
1239 1240 1241 1242 1243 1244 1245 | /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ | | > | > > | > > | | 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 | /* ** The xSavepoint() method. ** ** Flush the contents of the pending-terms table to disk. */ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5Table *pTab = (Fts5Table*)pVtab; fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint); return sqlite3Fts5IndexSync(pTab->pIndex, 0); } /* ** The xRelease() method. ** ** This is a no-op. */ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5Table *pTab = (Fts5Table*)pVtab; fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint); return sqlite3Fts5IndexSync(pTab->pIndex, 0); } /* ** The xRollbackTo() method. ** ** Discard the contents of the pending terms table. */ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ Fts5Table *pTab = (Fts5Table*)pVtab; fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint); return sqlite3Fts5IndexRollback(pTab->pIndex); } /* ** Register a new auxiliary function with global context pGlobal. */ int sqlite3Fts5CreateAux( Fts5Global *pGlobal, /* Global context (one per db handle) */ |
︙ | ︙ |
Changes to ext/fts5/fts5Int.h.
︙ | ︙ | |||
68 69 70 71 72 73 74 75 76 77 78 79 80 81 | void sqlite3Fts5Dequote(char *z); /* ** End of interface to code in fts5_config.c. **************************************************************************/ /************************************************************************** */ /* ** Buffer object for the incremental building of string data. */ typedef struct Fts5Buffer Fts5Buffer; struct Fts5Buffer { | > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | void sqlite3Fts5Dequote(char *z); /* ** End of interface to code in fts5_config.c. **************************************************************************/ /************************************************************************** ** Interface to code in fts5_buffer.c. */ /* ** Buffer object for the incremental building of string data. */ typedef struct Fts5Buffer Fts5Buffer; struct Fts5Buffer { |
︙ | ︙ | |||
152 153 154 155 156 157 158 | typedef struct Fts5IndexIter Fts5IndexIter; /* ** Values used as part of the flags argument passed to IndexQuery(). */ #define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ #define FTS5INDEX_QUERY_ASC 0x0002 /* Docs in ascending rowid order */ | < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | typedef struct Fts5IndexIter Fts5IndexIter; /* ** Values used as part of the flags argument passed to IndexQuery(). */ #define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */ #define FTS5INDEX_QUERY_ASC 0x0002 /* Docs in ascending rowid order */ /* ** Create/destroy an Fts5Index object. */ int sqlite3Fts5IndexOpen(Fts5Config *pConfig, int bCreate, Fts5Index**, char**); int sqlite3Fts5IndexClose(Fts5Index *p, int bDestroy); |
︙ | ︙ | |||
226 227 228 229 230 231 232 | void sqlite3Fts5IndexBeginWrite( Fts5Index *p, /* Index to write to */ i64 iDocid /* Docid to add or remove data from */ ); /* ** Flush any data stored in the in-memory hash tables to the database. | | < < < < | < < < | > | > | > > > > > > > < < | > > > | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | void sqlite3Fts5IndexBeginWrite( Fts5Index *p, /* Index to write to */ i64 iDocid /* Docid to add or remove data from */ ); /* ** Flush any data stored in the in-memory hash tables to the database. ** If the bCommit flag is true, also close any open blob handles. */ 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. */ int sqlite3Fts5IndexRollback(Fts5Index *p); /* ** Retrieve and clear the current error code, respectively. */ int sqlite3Fts5IndexErrcode(Fts5Index*); void sqlite3Fts5IndexReset(Fts5Index*); /* ** Get or set the "averages" record. */ int sqlite3Fts5IndexGetAverages(Fts5Index *p, Fts5Buffer *pBuf); int sqlite3Fts5IndexSetAverages(Fts5Index *p, const u8*, int); /* ** Functions called by the storage module as part of integrity-check. */ u64 sqlite3Fts5IndexCksum(Fts5Config*,i64,int,int,const char*,int); int sqlite3Fts5IndexIntegrityCheck(Fts5Index*, u64 cksum); /* ** 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); /* ** Return the total number of entries read from the %_data table by ** this connection since it was created. */ int sqlite3Fts5IndexReads(Fts5Index *p); /* ** End of interface to code in fts5_index.c. **************************************************************************/ /************************************************************************** |
︙ | ︙ |
Changes to ext/fts5/fts5_aux.c.
︙ | ︙ | |||
741 742 743 744 745 746 747 | if( nVal>=1 ){ zReq = (const char*)sqlite3_value_text(apVal[0]); } memset(&s, 0, sizeof(Fts5Buffer)); nCol = pApi->xColumnCount(pFts); | < > > > | < < > > > | < > < > > > | < < > > > | < < > > > | < < > > > | < < > > > | < < | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | if( nVal>=1 ){ zReq = (const char*)sqlite3_value_text(apVal[0]); } memset(&s, 0, sizeof(Fts5Buffer)); nCol = pApi->xColumnCount(pFts); /* ** 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++){ i64 colsz = 0; rc = pApi->xColumnTotalSize(pFts, i, &colsz); sqlite3Fts5BufferAppendPrintf(&rc, &s, "%s%d", i==0?"":" ", colsz); } if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "}"); } /* ** 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); } /* ** 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++){ int colsz = 0; rc = pApi->xColumnSize(pFts, i, &colsz); sqlite3Fts5BufferAppendPrintf(&rc, &s, "%s%d", i==0?"":" ", colsz); } if( zReq==0 && nCol>1 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, "}"); } /* ** 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; int n; rc = pApi->xColumnText(pFts, i, &z, &n); if( i!=0 ) sqlite3Fts5BufferAppendPrintf(&rc, &s, " "); sqlite3Fts5BufferAppendListElem(&rc, &s, z, n); } } /* ** 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); } /* ** 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); sqlite3Fts5BufferAppendPrintf(&rc, &s, "%d", nSize); }else{ sqlite3Fts5BufferAppendPrintf(&rc, &s, "{"); for(i=0; i<nPhrase; i++){ int nSize = pApi->xPhraseSize(pFts, i); sqlite3Fts5BufferAppendPrintf(&rc, &s, "%s%d", (i==0?"":" "), nSize); } sqlite3Fts5BufferAppendPrintf(&rc, &s, "}"); } } /* ** 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; i64 iPos = 0; int nElem = 0; |
︙ | ︙ |
Changes to ext/fts5/fts5_index.c.
︙ | ︙ | |||
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 | #if 0 Fts5Buffer buf = {0,0,0}; fts5DebugRowid(&rc, &buf, iRowid); fprintf(stdout, "read: %s\n", buf.p); fflush(stdout); sqlite3_free(buf.p); #endif /* If the blob handle is not yet open, open and seek it. Otherwise, use ** the blob_reopen() API to reseek the existing blob handle. */ if( p->pReader==0 ){ Fts5Config *pConfig = p->pConfig; rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader ); | > > > > > > > > > > < < | 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 | #if 0 Fts5Buffer buf = {0,0,0}; fts5DebugRowid(&rc, &buf, iRowid); 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. */ if( p->pReader==0 ){ Fts5Config *pConfig = p->pConfig; rc = sqlite3_blob_open(pConfig->db, pConfig->zDb, p->zDataTbl, "block", iRowid, 0, &p->pReader ); } if( rc ) fts5MissingData(); if( rc==SQLITE_OK ){ int nByte = sqlite3_blob_bytes(p->pReader); if( pBuf ){ |
︙ | ︙ | |||
2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 | } sqlite3_free(ap); fts3HashClear(pHash); return pList; } /* ** Return the size of the prefix, in bytes, that buffer (nNew/pNew) shares ** with buffer (nOld/pOld). */ static int fts5PrefixCompress( int nOld, const u8 *pOld, int nNew, const u8 *pNew | > > > > > > > > > > > > > > > > > > > | 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 | } sqlite3_free(ap); fts3HashClear(pHash); 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). */ static int fts5PrefixCompress( int nOld, const u8 *pOld, int nNew, const u8 *pNew |
︙ | ︙ | |||
3141 3142 3143 3144 3145 3146 3147 | } fts5IndexWork(p, iHash, pStruct, pgnoLast); fts5StructureWrite(p, iHash, pStruct); fts5StructureRelease(pStruct); } | < < < < < < < < < < < | > > > > > > > > > > > | | | > | 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 | } fts5IndexWork(p, iHash, pStruct, pgnoLast); fts5StructureWrite(p, iHash, pStruct); fts5StructureRelease(pStruct); } /* ** Flush any data stored in the in-memory hash tables to the database. */ static void fts5IndexFlush(Fts5Index *p){ Fts5Config *pConfig = p->pConfig; int i; /* Used to iterate through indexes */ int nLeaf = 0; /* Number of leaves written */ /* If an error has already occured this call is a no-op. */ if( p->rc!=SQLITE_OK || p->nPendingData==0 ) return; assert( p->aHash ); /* Flush the terms and each prefix index to disk */ for(i=0; i<=pConfig->nPrefix; i++){ fts5FlushOneHash(p, i, &nLeaf); } 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, int bCommit){ fts5IndexFlush(p); if( bCommit ) fts5CloseReader(p); return p->rc; } /* ** 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. */ int sqlite3Fts5IndexRollback(Fts5Index *p){ fts5CloseReader(p); fts5IndexDiscardData(p); return SQLITE_OK; } /* ** Open a new Fts5Index handle. If the bCreate argument is true, create ** and initialize the underlying %_data table. ** |
︙ | ︙ |
Added test/fts5ai.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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 |
Changes to test/permutations.test.
︙ | ︙ | |||
222 223 224 225 226 227 228 | fts4growth.test fts4growth2.test } test_suite "fts5" -prefix "" -description { All FTS5 tests. } -files { fts5aa.test fts5ab.test fts5ac.test fts5ad.test fts5ae.test fts5ea.test | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | fts4growth.test fts4growth2.test } 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 fts5ai.test } test_suite "nofaultsim" -prefix "" -description { "Very" quick test suite. Runs in less than 5 minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ |
︙ | ︙ |