From: dan Date: Thu, 1 Aug 2024 17:15:17 +0000 (+0000) Subject: Clarify the role of Fts5Storage.pSavedRow in the new feature on this branch. X-Git-Tag: version-3.47.0~220^2~23 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f971c15b1f48bd986da68c40602158e9669914ba;p=thirdparty%2Fsqlite.git Clarify the role of Fts5Storage.pSavedRow in the new feature on this branch. FossilOrigin-Name: e8a61d5c48073fdd4d99d0b6fc70469b37af009f281336a44e3789e7eeed820d --- diff --git a/ext/fts5/fts5_storage.c b/ext/fts5/fts5_storage.c index e55e2b833b..0a655d160f 100644 --- a/ext/fts5/fts5_storage.c +++ b/ext/fts5/fts5_storage.c @@ -16,6 +16,32 @@ #include "fts5Int.h" +/* +** pSavedRow: +** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it +** does a by-rowid lookup to retrieve a single row from the %_content +** table or equivalent external-content table/view. +** +** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original +** values for a row being UPDATEd. In that case, the SQL statement is +** not reset and pSavedRow is set to point at it. This is so that the +** insert operation that follows the delete may access the original +** row values for any new values for which sqlite3_value_nochange() returns +** true. i.e. if the user executes: +** +** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1); +** ... +** UPDATE fts SET a=?, b=? WHERE rowid=?; +** +** then the value passed to the xUpdate() method of this table as the +** new.c value is an sqlite3_value_nochange() value. So in this case it +** must be read from the saved row stored in Fts5Storage.pSavedRow. +** +** This is necessary - using sqlite3_value_nochange() instead of just having +** SQLite pass the original value back via xUpdate() - so as not to discard +** any locale information associated with such values. +** +*/ struct Fts5Storage { Fts5Config *pConfig; Fts5Index *pIndex; @@ -37,15 +63,15 @@ struct Fts5Storage { # error "FTS5_STMT_LOOKUP mismatch" #endif -#define FTS5_STMT_LOOKUP2 3 +#define FTS5_STMT_LOOKUP2 3 #define FTS5_STMT_INSERT_CONTENT 4 #define FTS5_STMT_REPLACE_CONTENT 5 #define FTS5_STMT_DELETE_CONTENT 6 -#define FTS5_STMT_REPLACE_DOCSIZE 7 +#define FTS5_STMT_REPLACE_DOCSIZE 7 #define FTS5_STMT_DELETE_DOCSIZE 8 #define FTS5_STMT_LOOKUP_DOCSIZE 9 #define FTS5_STMT_REPLACE_CONFIG 10 -#define FTS5_STMT_SCAN 11 +#define FTS5_STMT_SCAN 11 /* ** Prepare the two insert statements - Fts5Storage.pInsertContent and @@ -405,6 +431,16 @@ static int fts5StorageInsertCallback( return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); } +/* +** This function is used as part of an UPDATE statement that modifies the +** rowid of a row. In that case, this function is called first to set +** Fts5Storage.pSavedRow to point to a statement that may be used to +** access the original values of the row being deleted - iDel. +** +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. +** It is not considered an error if row iDel does not exist. In this case +** pSavedRow is not set and SQLITE_OK returned. +*/ int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){ int rc = SQLITE_OK; sqlite3_stmt *pSeek = 0; @@ -427,12 +463,17 @@ int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){ ** If a row with rowid iDel is present in the %_content table, add the ** delete-markers to the FTS index necessary to delete it. Do not actually ** remove the %_content row at this time though. +** +** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left +** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access +** the original values of the row being deleted. This is used by UPDATE +** statements. */ static int fts5StorageDeleteFromIndex( Fts5Storage *p, i64 iDel, sqlite3_value **apVal, - int bSaveRow + int bSaveRow /* True to set pSavedRow */ ){ Fts5Config *pConfig = p->pConfig; sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ @@ -506,7 +547,15 @@ static int fts5StorageDeleteFromIndex( return rc; } +/* +** Reset any saved statement pSavedRow. Zero pSavedRow as well. This +** should be called by the xUpdate() method of the fts5 table before +** returning from any operation that may have set Fts5Storage.pSavedRow. +*/ void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){ + assert( pStorage->pSavedRow==0 + || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2] + ); sqlite3_reset(pStorage->pSavedRow); pStorage->pSavedRow = 0; } @@ -630,7 +679,7 @@ int sqlite3Fts5StorageDelete( Fts5Storage *p, /* Storage object */ i64 iDel, /* Rowid to delete from table */ sqlite3_value **apVal, /* Optional - values to remove from index */ - int bSaveRow + int bSaveRow /* If true, set pSavedRow for deleted row */ ){ Fts5Config *pConfig = p->pConfig; int rc; @@ -737,13 +786,12 @@ int sqlite3Fts5StorageRebuild(Fts5Storage *p){ for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - int bReset = 0; - int nText = 0; - const char *pText = 0; - rc = sqlite3Fts5ExtractText(pConfig, - sqlite3_column_value(pScan, ctx.iCol+1), 1, &bReset, &pText, &nText - ); + int bReset = 0; /* True if tokenizer locale must be reset */ + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ + sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1); + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText); if( rc==SQLITE_OK ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, @@ -838,6 +886,8 @@ int sqlite3Fts5StorageContentInsert( for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ sqlite3_value *pVal = apVal[i]; if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ + /* This is an UPDATE statement, and column (i-2) was not modified. + ** Retrieve the value from Fts5Storage.pSavedRow instead. */ pVal = sqlite3_column_value(p->pSavedRow, i-1); }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){ if( pConfig->bLocale==0 ){ @@ -859,7 +909,8 @@ int sqlite3Fts5StorageContentInsert( && sqlite3_value_type(pVal)==SQLITE_BLOB && i>=2 && pConfig->abUnindexed[i-2]==0 ){ - /* Inserting a blob into a normal content table with locale=1. */ + /* Inserting a blob into a normal content table with locale=1. + ** Add the 4 0x00 byte header. */ int n = sqlite3_value_bytes(pVal); u8 *pBlob = sqlite3Fts5MallocZero(&rc, n+4); if( pBlob ){ @@ -905,28 +956,22 @@ int sqlite3Fts5StorageIndexInsert( for(ctx.iCol=0; rc==SQLITE_OK && ctx.iColnCol; ctx.iCol++){ ctx.szCol = 0; if( pConfig->abUnindexed[ctx.iCol]==0 ){ - int bReset = 0; - int nText = 0; - const char *pText = 0; + int bReset = 0; /* True if tokenizer locale must be reset */ + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ sqlite3_value *pVal = apVal[ctx.iCol+2]; int bDisk = 0; if( p->pSavedRow && sqlite3_value_nochange(pVal) ){ pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1); bDisk = 1; } - rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset,&pText,&nText); + rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText); if( rc==SQLITE_OK ){ - if( bReset && pConfig->bLocale==0 ){ - rc = SQLITE_ERROR; - sqlite3Fts5ConfigErrmsg(pConfig, - "fts5_locale() may not be used without locale=1" - ); - }else{ - rc = sqlite3Fts5Tokenize(pConfig, - FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, - fts5StorageInsertCallback - ); - } + assert( bReset==0 || pConfig->bLocale ); + rc = sqlite3Fts5Tokenize(pConfig, + FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, + fts5StorageInsertCallback + ); if( bReset ) sqlite3Fts5ClearLocale(pConfig); } } @@ -1099,14 +1144,13 @@ int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg){ rc = sqlite3Fts5TermsetNew(&ctx.pTermset); } if( rc==SQLITE_OK ){ - const char *pText = 0; - int nText = 0; - int bReset = 0; + int bReset = 0; /* True if tokenizer locale must be reset */ + int nText = 0; /* Size of pText in bytes */ + const char *pText = 0; /* Pointer to buffer containing text value */ rc = sqlite3Fts5ExtractText(pConfig, sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText ); - if( rc==SQLITE_OK ){ rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, diff --git a/manifest b/manifest index 9a70fc55a7..fc335fa46f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\svarious\sproblems\swith\sthe\scode\son\sthis\sbranch. -D 2024-07-31T20:49:00.656 +C Clarify\sthe\srole\sof\sFts5Storage.pSavedRow\sin\sthe\snew\sfeature\son\sthis\sbranch. +D 2024-08-01T17:15:17.507 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -101,7 +101,7 @@ F ext/fts5/fts5_expr.c c7336d5f9ecc0e2b014d700be2bec0ea383b0e82c494a7c5c4ac62232 F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1 F ext/fts5/fts5_index.c eb9a0dda3bc6ef969a6be8d2746af56856e67251810ddba08622b45be8477abe F ext/fts5/fts5_main.c bda8d421024191376343a571370a7b2f92fdf5303e32c6dc0d7456bef9ffedd8 -F ext/fts5/fts5_storage.c f94b924db1bc164af3feadcc3f08f0d8f5da5cd45e4909313637aeee85d0d13c +F ext/fts5/fts5_storage.c 784c6c4edf676c831ffbaef7b0484dcafe925d3d39049b8ee6b6eeaadae1b042 F ext/fts5/fts5_tcl.c 93b705cb87633574983161edc5234f9b91ba03f9fecfbd2c5d401a1da6f93aa5 F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b @@ -2201,8 +2201,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P fa0da3b28e411affd45a918d6b7faba49f744ca8b4adf3cd5ce6609bb630499e -R 4281c2d6e2e80158745c4320fdfed09d +P 8bd4ae7e95c7b6ce34db5ea705dc136e742a22f333d0e7370b485ebd736b5ec2 +R 65a2f69590c259e395cd85b8f6d4acad U dan -Z 7ae6a6ddbc4056daf1c0903e2b7934cf +Z cbe99cb860ae582ece42e3b6610aa855 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index dee0563fc6..0c89f035e2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8bd4ae7e95c7b6ce34db5ea705dc136e742a22f333d0e7370b485ebd736b5ec2 +e8a61d5c48073fdd4d99d0b6fc70469b37af009f281336a44e3789e7eeed820d