Add support for savepoints to fts5.
FossilOrigin-Name: 3b19eba042bb2eeb1be60f8d58ebaa0a045d6a5c
This commit is contained in:
+119
-6
@@ -13,14 +13,52 @@
|
||||
** 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+19
-16
@@ -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);
|
||||
|
||||
/*
|
||||
|
||||
+29
-22
@@ -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;
|
||||
|
||||
+45
-17
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user