]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Clarify the role of Fts5Storage.pSavedRow in the new feature on this branch.
authordan <Dan Kennedy>
Thu, 1 Aug 2024 17:15:17 +0000 (17:15 +0000)
committerdan <Dan Kennedy>
Thu, 1 Aug 2024 17:15:17 +0000 (17:15 +0000)
FossilOrigin-Name: e8a61d5c48073fdd4d99d0b6fc70469b37af009f281336a44e3789e7eeed820d

ext/fts5/fts5_storage.c
manifest
manifest.uuid

index e55e2b833b36ba93e37372054a01f1bb1ed601a4..0a655d160f1eca6e90c867e1c8433f8ee1f41bd2 100644 (file)
 
 #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.iCol<pConfig->nCol; 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.iCol<pConfig->nCol; 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,
index 9a70fc55a74e44cce4f60aea2f4fcecdbfd2efcb..fc335fa46f0ea74b1c3438ab0da8d3a2fc2f2cb1 100644 (file)
--- 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.
index dee0563fc69f0e16cd31e371759dd8448a4252ba..0c89f035e2f003e211a3db29ea0744101bac7636 100644 (file)
@@ -1 +1 @@
-8bd4ae7e95c7b6ce34db5ea705dc136e742a22f333d0e7370b485ebd736b5ec2
+e8a61d5c48073fdd4d99d0b6fc70469b37af009f281336a44e3789e7eeed820d