Avoid preparing a SELECT statement each time an UPDATE or DELETE
by docid is executed against an fts3 table. FossilOrigin-Name: 9962c10a5c6672bd82b2bf640d878fcdac0b815a
This commit is contained in:
+36
-14
@@ -492,6 +492,7 @@ static int fts3DisconnectMethod(sqlite3_vtab *pVtab){
|
||||
assert( p->pSegments==0 );
|
||||
|
||||
/* Free any prepared statements held */
|
||||
sqlite3_finalize(p->pSeekStmt);
|
||||
for(i=0; i<SizeofArray(p->aStmt); i++){
|
||||
sqlite3_finalize(p->aStmt[i]);
|
||||
}
|
||||
@@ -1680,6 +1681,26 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finalize the statement handle at pCsr->pStmt.
|
||||
**
|
||||
** Or, if that statement handle is one created by fts3CursorSeekStmt(),
|
||||
** and the Fts3Table.pSeekStmt slot is currently NULL, save the statement
|
||||
** pointer there instead of finalizing it.
|
||||
*/
|
||||
static void fts3CursorFinalizeStmt(Fts3Cursor *pCsr){
|
||||
if( pCsr->bSeekStmt ){
|
||||
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
|
||||
if( p->pSeekStmt==0 ){
|
||||
p->pSeekStmt = pCsr->pStmt;
|
||||
sqlite3_reset(pCsr->pStmt);
|
||||
pCsr->pStmt = 0;
|
||||
}
|
||||
pCsr->bSeekStmt = 0;
|
||||
}
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Close the cursor. For additional information see the documentation
|
||||
** on the xClose method of the virtual table interface.
|
||||
@@ -1687,7 +1708,7 @@ static int fts3OpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){
|
||||
static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
Fts3Cursor *pCsr = (Fts3Cursor *)pCursor;
|
||||
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
fts3CursorFinalizeStmt(pCsr);
|
||||
sqlite3Fts3ExprFree(pCsr->pExpr);
|
||||
sqlite3Fts3FreeDeferredTokens(pCsr);
|
||||
sqlite3_free(pCsr->aDoclist);
|
||||
@@ -1705,20 +1726,23 @@ static int fts3CloseMethod(sqlite3_vtab_cursor *pCursor){
|
||||
**
|
||||
** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
|
||||
** it. If an error occurs, return an SQLite error code.
|
||||
**
|
||||
** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
|
||||
*/
|
||||
static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
|
||||
static int fts3CursorSeekStmt(Fts3Cursor *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->pStmt==0 ){
|
||||
Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
|
||||
char *zSql;
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( p->pSeekStmt ){
|
||||
pCsr->pStmt = p->pSeekStmt;
|
||||
p->pSeekStmt = 0;
|
||||
}else{
|
||||
zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
|
||||
if( !zSql ) return SQLITE_NOMEM;
|
||||
rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
}
|
||||
if( rc==SQLITE_OK ) pCsr->bSeekStmt = 1;
|
||||
}
|
||||
*ppStmt = pCsr->pStmt;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1730,9 +1754,7 @@ static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
|
||||
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
|
||||
int rc = SQLITE_OK;
|
||||
if( pCsr->isRequireSeek ){
|
||||
sqlite3_stmt *pStmt = 0;
|
||||
|
||||
rc = fts3CursorSeekStmt(pCsr, &pStmt);
|
||||
rc = fts3CursorSeekStmt(pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
|
||||
pCsr->isRequireSeek = 0;
|
||||
@@ -3190,7 +3212,7 @@ static int fts3FilterMethod(
|
||||
assert( iIdx==nVal );
|
||||
|
||||
/* In case the cursor has been used before, clear it now. */
|
||||
sqlite3_finalize(pCsr->pStmt);
|
||||
fts3CursorFinalizeStmt(pCsr);
|
||||
sqlite3_free(pCsr->aDoclist);
|
||||
sqlite3Fts3MIBufferFree(pCsr->pMIBuffer);
|
||||
sqlite3Fts3ExprFree(pCsr->pExpr);
|
||||
@@ -3258,7 +3280,7 @@ static int fts3FilterMethod(
|
||||
rc = SQLITE_NOMEM;
|
||||
}
|
||||
}else if( eSearch==FTS3_DOCID_SEARCH ){
|
||||
rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
|
||||
rc = fts3CursorSeekStmt(pCsr);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_bind_value(pCsr->pStmt, 1, pCons);
|
||||
}
|
||||
|
||||
@@ -230,6 +230,7 @@ struct Fts3Table {
|
||||
** statements is run and reset within a single virtual table API call.
|
||||
*/
|
||||
sqlite3_stmt *aStmt[40];
|
||||
sqlite3_stmt *pSeekStmt; /* Cache for fts3CursorSeekStmt() */
|
||||
|
||||
char *zReadExprlist;
|
||||
char *zWriteExprlist;
|
||||
@@ -299,6 +300,7 @@ struct Fts3Cursor {
|
||||
i16 eSearch; /* Search strategy (see below) */
|
||||
u8 isEof; /* True if at End Of Results */
|
||||
u8 isRequireSeek; /* True if must seek pStmt to %_content row */
|
||||
u8 bSeekStmt; /* True if pStmt is a seek */
|
||||
sqlite3_stmt *pStmt; /* Prepared statement in use by the cursor */
|
||||
Fts3Expr *pExpr; /* Parsed MATCH query string */
|
||||
int iLangid; /* Language being queried for */
|
||||
|
||||
Reference in New Issue
Block a user