| | @@ -16,11 +16,11 @@ |
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | | -** cf61cd359e666c66b6bba4407a653c799f7f with changes in files: |
| 21 | +** 6a5701e6c7be25cba93e55438f950966e1da with changes in files: |
| 22 | 22 | ** |
| 23 | 23 | ** |
| 24 | 24 | */ |
| 25 | 25 | #ifndef SQLITE_AMALGAMATION |
| 26 | 26 | #define SQLITE_CORE 1 |
| | @@ -465,11 +465,11 @@ |
| 465 | 465 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 466 | 466 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 467 | 467 | */ |
| 468 | 468 | #define SQLITE_VERSION "3.51.0" |
| 469 | 469 | #define SQLITE_VERSION_NUMBER 3051000 |
| 470 | | -#define SQLITE_SOURCE_ID "2025-06-23 16:51:33 cf61cd359e666c66b6bba4407a653c799f7f07e1f5ee6b837ad467029c461a6a" |
| 470 | +#define SQLITE_SOURCE_ID "2025-06-24 15:58:32 6a5701e6c7be25cba93e55438f950966e1dacb32eb2b23a8acc8ac53da6f0a85" |
| 471 | 471 | |
| 472 | 472 | /* |
| 473 | 473 | ** CAPI3REF: Run-Time Library Version Numbers |
| 474 | 474 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 475 | 475 | ** |
| | @@ -4479,19 +4479,19 @@ |
| 4479 | 4479 | ** The application does not need to worry about freeing the result. |
| 4480 | 4480 | ** However, the error string might be overwritten or deallocated by |
| 4481 | 4481 | ** subsequent calls to other SQLite interface functions.)^ |
| 4482 | 4482 | ** |
| 4483 | 4483 | ** ^The sqlite3_errstr(E) interface returns the English-language text |
| 4484 | | -** that describes the [result code] E, as UTF-8, or NULL if E is not an |
| 4484 | +** that describes the [result code] E, as UTF-8, or NULL if E is not a |
| 4485 | 4485 | ** result code for which a text error message is available. |
| 4486 | 4486 | ** ^(Memory to hold the error message string is managed internally |
| 4487 | 4487 | ** and must not be freed by the application)^. |
| 4488 | 4488 | ** |
| 4489 | 4489 | ** ^If the most recent error references a specific token in the input |
| 4490 | 4490 | ** SQL, the sqlite3_error_offset() interface returns the byte offset |
| 4491 | 4491 | ** of the start of that token. ^The byte offset returned by |
| 4492 | | -** sqlite3_error_offset() assumes that the input SQL is UTF8. |
| 4492 | +** sqlite3_error_offset() assumes that the input SQL is UTF-8. |
| 4493 | 4493 | ** ^If the most recent error does not reference a specific token in the input |
| 4494 | 4494 | ** SQL, then the sqlite3_error_offset() function returns -1. |
| 4495 | 4495 | ** |
| 4496 | 4496 | ** When the serialized [threading mode] is in use, it might be the |
| 4497 | 4497 | ** case that a second error occurs on a separate thread in between |
| | @@ -4586,12 +4586,12 @@ |
| 4586 | 4586 | ** CAPI3REF: Run-Time Limit Categories |
| 4587 | 4587 | ** KEYWORDS: {limit category} {*limit categories} |
| 4588 | 4588 | ** |
| 4589 | 4589 | ** These constants define various performance limits |
| 4590 | 4590 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 4591 | | -** The synopsis of the meanings of the various limits is shown below. |
| 4592 | | -** Additional information is available at [limits | Limits in SQLite]. |
| 4591 | +** A concise description of these limits follows, and additional information |
| 4592 | +** is available at [limits | Limits in SQLite]. |
| 4593 | 4593 | ** |
| 4594 | 4594 | ** <dl> |
| 4595 | 4595 | ** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> |
| 4596 | 4596 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 4597 | 4597 | ** |
| | @@ -4652,11 +4652,11 @@ |
| 4652 | 4652 | #define SQLITE_LIMIT_WORKER_THREADS 11 |
| 4653 | 4653 | |
| 4654 | 4654 | /* |
| 4655 | 4655 | ** CAPI3REF: Prepare Flags |
| 4656 | 4656 | ** |
| 4657 | | -** These constants define various flags that can be passed into |
| 4657 | +** These constants define various flags that can be passed into the |
| 4658 | 4658 | ** "prepFlags" parameter of the [sqlite3_prepare_v3()] and |
| 4659 | 4659 | ** [sqlite3_prepare16_v3()] interfaces. |
| 4660 | 4660 | ** |
| 4661 | 4661 | ** New flags may be added in future releases of SQLite. |
| 4662 | 4662 | ** |
| | @@ -4739,11 +4739,11 @@ |
| 4739 | 4739 | ** statement is generated. |
| 4740 | 4740 | ** If the caller knows that the supplied string is nul-terminated, then |
| 4741 | 4741 | ** there is a small performance advantage to passing an nByte parameter that |
| 4742 | 4742 | ** is the number of bytes in the input string <i>including</i> |
| 4743 | 4743 | ** the nul-terminator. |
| 4744 | | -** Note that nByte measure the length of the input in bytes, not |
| 4744 | +** Note that nByte measures the length of the input in bytes, not |
| 4745 | 4745 | ** characters, even for the UTF-16 interfaces. |
| 4746 | 4746 | ** |
| 4747 | 4747 | ** ^If pzTail is not NULL then *pzTail is made to point to the first byte |
| 4748 | 4748 | ** past the end of the first SQL statement in zSql. These routines only |
| 4749 | 4749 | ** compile the first statement in zSql, so *pzTail is left pointing to |
| | @@ -4873,11 +4873,11 @@ |
| 4873 | 4873 | ** the original string, "SELECT $abc,:xyz" but sqlite3_expanded_sql() |
| 4874 | 4874 | ** will return "SELECT 2345,NULL".)^ |
| 4875 | 4875 | ** |
| 4876 | 4876 | ** ^The sqlite3_expanded_sql() interface returns NULL if insufficient memory |
| 4877 | 4877 | ** is available to hold the result, or if the result would exceed the |
| 4878 | | -** the maximum string length determined by the [SQLITE_LIMIT_LENGTH]. |
| 4878 | +** maximum string length determined by the [SQLITE_LIMIT_LENGTH]. |
| 4879 | 4879 | ** |
| 4880 | 4880 | ** ^The [SQLITE_TRACE_SIZE_LIMIT] compile-time option limits the size of |
| 4881 | 4881 | ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time |
| 4882 | 4882 | ** option causes sqlite3_expanded_sql() to always return NULL. |
| 4883 | 4883 | ** |
| | @@ -5061,11 +5061,11 @@ |
| 5061 | 5061 | /* |
| 5062 | 5062 | ** CAPI3REF: SQL Function Context Object |
| 5063 | 5063 | ** |
| 5064 | 5064 | ** The context in which an SQL function executes is stored in an |
| 5065 | 5065 | ** sqlite3_context object. ^A pointer to an sqlite3_context object |
| 5066 | | -** is always first parameter to [application-defined SQL functions]. |
| 5066 | +** is always the first parameter to [application-defined SQL functions]. |
| 5067 | 5067 | ** The application-defined SQL function implementation will pass this |
| 5068 | 5068 | ** pointer through into calls to [sqlite3_result_int | sqlite3_result()], |
| 5069 | 5069 | ** [sqlite3_aggregate_context()], [sqlite3_user_data()], |
| 5070 | 5070 | ** [sqlite3_context_db_handle()], [sqlite3_get_auxdata()], |
| 5071 | 5071 | ** and/or [sqlite3_set_auxdata()]. |
| | @@ -5798,11 +5798,11 @@ |
| 5798 | 5798 | ** CAPI3REF: Destroy A Prepared Statement Object |
| 5799 | 5799 | ** DESTRUCTOR: sqlite3_stmt |
| 5800 | 5800 | ** |
| 5801 | 5801 | ** ^The sqlite3_finalize() function is called to delete a [prepared statement]. |
| 5802 | 5802 | ** ^If the most recent evaluation of the statement encountered no errors |
| 5803 | | -** or if the statement is never been evaluated, then sqlite3_finalize() returns |
| 5803 | +** or if the statement has never been evaluated, then sqlite3_finalize() returns |
| 5804 | 5804 | ** SQLITE_OK. ^If the most recent evaluation of statement S failed, then |
| 5805 | 5805 | ** sqlite3_finalize(S) returns the appropriate [error code] or |
| 5806 | 5806 | ** [extended error code]. |
| 5807 | 5807 | ** |
| 5808 | 5808 | ** ^The sqlite3_finalize(S) routine can be called at any point during |
| | @@ -6030,11 +6030,11 @@ |
| 6030 | 6030 | ); |
| 6031 | 6031 | |
| 6032 | 6032 | /* |
| 6033 | 6033 | ** CAPI3REF: Text Encodings |
| 6034 | 6034 | ** |
| 6035 | | -** These constant define integer codes that represent the various |
| 6035 | +** These constants define integer codes that represent the various |
| 6036 | 6036 | ** text encodings supported by SQLite. |
| 6037 | 6037 | */ |
| 6038 | 6038 | #define SQLITE_UTF8 1 /* IMP: R-37514-35566 */ |
| 6039 | 6039 | #define SQLITE_UTF16LE 2 /* IMP: R-03371-37637 */ |
| 6040 | 6040 | #define SQLITE_UTF16BE 3 /* IMP: R-51971-34154 */ |
| | @@ -6122,11 +6122,11 @@ |
| 6122 | 6122 | ** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call |
| 6123 | 6123 | ** [sqlite3_result_subtype()] to cause a sub-type to be associated with its |
| 6124 | 6124 | ** result. |
| 6125 | 6125 | ** Every function that invokes [sqlite3_result_subtype()] should have this |
| 6126 | 6126 | ** property. If it does not, then the call to [sqlite3_result_subtype()] |
| 6127 | | -** might become a no-op if the function is used as term in an |
| 6127 | +** might become a no-op if the function is used as a term in an |
| 6128 | 6128 | ** [expression index]. On the other hand, SQL functions that never invoke |
| 6129 | 6129 | ** [sqlite3_result_subtype()] should avoid setting this property, as the |
| 6130 | 6130 | ** purpose of this property is to disable certain optimizations that are |
| 6131 | 6131 | ** incompatible with subtypes. |
| 6132 | 6132 | ** |
| | @@ -6249,11 +6249,11 @@ |
| 6249 | 6249 | ** |
| 6250 | 6250 | ** ^Within the [xUpdate] method of a [virtual table], the |
| 6251 | 6251 | ** sqlite3_value_nochange(X) interface returns true if and only if |
| 6252 | 6252 | ** the column corresponding to X is unchanged by the UPDATE operation |
| 6253 | 6253 | ** that the xUpdate method call was invoked to implement and if |
| 6254 | | -** and the prior [xColumn] method call that was invoked to extracted |
| 6254 | +** the prior [xColumn] method call that was invoked to extract |
| 6255 | 6255 | ** the value for that column returned without setting a result (probably |
| 6256 | 6256 | ** because it queried [sqlite3_vtab_nochange()] and found that the column |
| 6257 | 6257 | ** was unchanging). ^Within an [xUpdate] method, any value for which |
| 6258 | 6258 | ** sqlite3_value_nochange(X) is true will in all other respects appear |
| 6259 | 6259 | ** to be a NULL value. If sqlite3_value_nochange(X) is invoked anywhere other |
| | @@ -93753,10 +93753,13 @@ |
| 93753 | 93753 | rc = SQLITE_MISUSE_BKPT; |
| 93754 | 93754 | goto preupdate_old_out; |
| 93755 | 93755 | } |
| 93756 | 93756 | if( p->pPk ){ |
| 93757 | 93757 | iStore = sqlite3TableColumnToIndex(p->pPk, iIdx); |
| 93758 | + }else if( iIdx >= p->pTab->nCol ){ |
| 93759 | + rc = SQLITE_MISUSE_BKPT; |
| 93760 | + goto preupdate_old_out; |
| 93758 | 93761 | }else{ |
| 93759 | 93762 | iStore = sqlite3TableColumnToStorage(p->pTab, iIdx); |
| 93760 | 93763 | } |
| 93761 | 93764 | if( iStore>=p->pCsr->nField || iStore<0 ){ |
| 93762 | 93765 | rc = SQLITE_RANGE; |
| | @@ -244933,10 +244936,40 @@ |
| 244933 | 244936 | Fts5Buffer term; /* Current term */ |
| 244934 | 244937 | i64 iRowid; /* Current rowid */ |
| 244935 | 244938 | int nPos; /* Number of bytes in current position list */ |
| 244936 | 244939 | u8 bDel; /* True if the delete flag is set */ |
| 244937 | 244940 | }; |
| 244941 | + |
| 244942 | +static int fts5IndexCorruptRowid(Fts5Index *pIdx, i64 iRowid){ |
| 244943 | + pIdx->rc = FTS5_CORRUPT; |
| 244944 | + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, |
| 244945 | + "fts5: corruption found reading blob %lld from table \"%s\"", |
| 244946 | + iRowid, pIdx->pConfig->zName |
| 244947 | + ); |
| 244948 | + return SQLITE_CORRUPT_VTAB; |
| 244949 | +} |
| 244950 | +#define FTS5_CORRUPT_ROWID(pIdx, iRowid) fts5IndexCorruptRowid(pIdx, iRowid) |
| 244951 | + |
| 244952 | +static int fts5IndexCorruptIter(Fts5Index *pIdx, Fts5SegIter *pIter){ |
| 244953 | + pIdx->rc = FTS5_CORRUPT; |
| 244954 | + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, |
| 244955 | + "fts5: corruption on page %d, segment %d, table \"%s\"", |
| 244956 | + pIter->iLeafPgno, pIter->pSeg->iSegid, pIdx->pConfig->zName |
| 244957 | + ); |
| 244958 | + return SQLITE_CORRUPT_VTAB; |
| 244959 | +} |
| 244960 | +#define FTS5_CORRUPT_ITER(pIdx, pIter) fts5IndexCorruptIter(pIdx, pIter) |
| 244961 | + |
| 244962 | +static int fts5IndexCorruptIdx(Fts5Index *pIdx){ |
| 244963 | + pIdx->rc = FTS5_CORRUPT; |
| 244964 | + sqlite3Fts5ConfigErrmsg(pIdx->pConfig, |
| 244965 | + "fts5: corruption in table \"%s\"", pIdx->pConfig->zName |
| 244966 | + ); |
| 244967 | + return SQLITE_CORRUPT_VTAB; |
| 244968 | +} |
| 244969 | +#define FTS5_CORRUPT_IDX(pIdx) fts5IndexCorruptIdx(pIdx) |
| 244970 | + |
| 244938 | 244971 | |
| 244939 | 244972 | /* |
| 244940 | 244973 | ** Array of tombstone pages. Reference counted. |
| 244941 | 244974 | */ |
| 244942 | 244975 | struct Fts5TombstoneArray { |
| | @@ -245223,11 +245256,11 @@ |
| 245223 | 245256 | /* If either of the sqlite3_blob_open() or sqlite3_blob_reopen() calls |
| 245224 | 245257 | ** above returned SQLITE_ERROR, return SQLITE_CORRUPT_VTAB instead. |
| 245225 | 245258 | ** All the reasons those functions might return SQLITE_ERROR - missing |
| 245226 | 245259 | ** table, missing row, non-blob/text in block column - indicate |
| 245227 | 245260 | ** backing store corruption. */ |
| 245228 | | - if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT; |
| 245261 | + if( rc==SQLITE_ERROR ) rc = FTS5_CORRUPT_ROWID(p, iRowid); |
| 245229 | 245262 | |
| 245230 | 245263 | if( rc==SQLITE_OK ){ |
| 245231 | 245264 | u8 *aOut = 0; /* Read blob data into this buffer */ |
| 245232 | 245265 | int nByte = sqlite3_blob_bytes(p->pReader); |
| 245233 | 245266 | int szData = (sizeof(Fts5Data) + 7) & ~7; |
| | @@ -245273,11 +245306,11 @@ |
| 245273 | 245306 | |
| 245274 | 245307 | static Fts5Data *fts5LeafRead(Fts5Index *p, i64 iRowid){ |
| 245275 | 245308 | Fts5Data *pRet = fts5DataRead(p, iRowid); |
| 245276 | 245309 | if( pRet ){ |
| 245277 | 245310 | if( pRet->nn<4 || pRet->szLeaf>pRet->nn ){ |
| 245278 | | - p->rc = FTS5_CORRUPT; |
| 245311 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 245279 | 245312 | fts5DataRelease(pRet); |
| 245280 | 245313 | pRet = 0; |
| 245281 | 245314 | } |
| 245282 | 245315 | } |
| 245283 | 245316 | return pRet; |
| | @@ -245632,12 +245665,18 @@ |
| 245632 | 245665 | pData = fts5DataRead(p, FTS5_STRUCTURE_ROWID); |
| 245633 | 245666 | if( p->rc==SQLITE_OK ){ |
| 245634 | 245667 | /* TODO: Do we need this if the leaf-index is appended? Probably... */ |
| 245635 | 245668 | memset(&pData->p[pData->nn], 0, FTS5_DATA_PADDING); |
| 245636 | 245669 | p->rc = fts5StructureDecode(pData->p, pData->nn, &iCookie, &pRet); |
| 245637 | | - if( p->rc==SQLITE_OK && (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ |
| 245638 | | - p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); |
| 245670 | + if( p->rc==SQLITE_OK ){ |
| 245671 | + if( (pConfig->pgsz==0 || pConfig->iCookie!=iCookie) ){ |
| 245672 | + p->rc = sqlite3Fts5ConfigLoad(pConfig, iCookie); |
| 245673 | + } |
| 245674 | + }else if( p->rc==SQLITE_CORRUPT_VTAB ){ |
| 245675 | + sqlite3Fts5ConfigErrmsg(p->pConfig, |
| 245676 | + "fts5: corrupt structure record for table \"%s\"", p->pConfig->zName |
| 245677 | + ); |
| 245639 | 245678 | } |
| 245640 | 245679 | fts5DataRelease(pData); |
| 245641 | 245680 | if( p->rc!=SQLITE_OK ){ |
| 245642 | 245681 | fts5StructureRelease(pRet); |
| 245643 | 245682 | pRet = 0; |
| | @@ -246256,11 +246295,11 @@ |
| 246256 | 246295 | |
| 246257 | 246296 | ASSERT_SZLEAF_OK(pIter->pLeaf); |
| 246258 | 246297 | while( iOff>=pIter->pLeaf->szLeaf ){ |
| 246259 | 246298 | fts5SegIterNextPage(p, pIter); |
| 246260 | 246299 | if( pIter->pLeaf==0 ){ |
| 246261 | | - if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; |
| 246300 | + if( p->rc==SQLITE_OK ) FTS5_CORRUPT_ITER(p, pIter); |
| 246262 | 246301 | return; |
| 246263 | 246302 | } |
| 246264 | 246303 | iOff = 4; |
| 246265 | 246304 | a = pIter->pLeaf->p; |
| 246266 | 246305 | } |
| | @@ -246288,11 +246327,11 @@ |
| 246288 | 246327 | i64 iOff = pIter->iLeafOffset; /* Offset to read at */ |
| 246289 | 246328 | int nNew; /* Bytes of new data */ |
| 246290 | 246329 | |
| 246291 | 246330 | iOff += fts5GetVarint32(&a[iOff], nNew); |
| 246292 | 246331 | if( iOff+nNew>pIter->pLeaf->szLeaf || nKeep>pIter->term.n || nNew==0 ){ |
| 246293 | | - p->rc = FTS5_CORRUPT; |
| 246332 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246294 | 246333 | return; |
| 246295 | 246334 | } |
| 246296 | 246335 | pIter->term.n = nKeep; |
| 246297 | 246336 | fts5BufferAppendBlob(&p->rc, &pIter->term, nNew, &a[iOff]); |
| 246298 | 246337 | assert( pIter->term.n<=pIter->term.nSpace ); |
| | @@ -246483,11 +246522,11 @@ |
| 246483 | 246522 | }else{ |
| 246484 | 246523 | int iRowidOff; |
| 246485 | 246524 | iRowidOff = fts5LeafFirstRowidOff(pNew); |
| 246486 | 246525 | if( iRowidOff ){ |
| 246487 | 246526 | if( iRowidOff>=pNew->szLeaf ){ |
| 246488 | | - p->rc = FTS5_CORRUPT; |
| 246527 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246489 | 246528 | }else{ |
| 246490 | 246529 | pIter->pLeaf = pNew; |
| 246491 | 246530 | pIter->iLeafOffset = iRowidOff; |
| 246492 | 246531 | } |
| 246493 | 246532 | } |
| | @@ -246717,11 +246756,11 @@ |
| 246717 | 246756 | pIter->iEndofDoclist = iOff; |
| 246718 | 246757 | bNewTerm = 1; |
| 246719 | 246758 | } |
| 246720 | 246759 | assert_nc( iOff<pLeaf->szLeaf ); |
| 246721 | 246760 | if( iOff>pLeaf->szLeaf ){ |
| 246722 | | - p->rc = FTS5_CORRUPT; |
| 246761 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246723 | 246762 | return; |
| 246724 | 246763 | } |
| 246725 | 246764 | } |
| 246726 | 246765 | } |
| 246727 | 246766 | |
| | @@ -246827,11 +246866,11 @@ |
| 246827 | 246866 | fts5DataRelease(pIter->pLeaf); |
| 246828 | 246867 | pIter->pLeaf = pLast; |
| 246829 | 246868 | pIter->iLeafPgno = pgnoLast; |
| 246830 | 246869 | iOff = fts5LeafFirstRowidOff(pLast); |
| 246831 | 246870 | if( iOff>pLast->szLeaf ){ |
| 246832 | | - p->rc = FTS5_CORRUPT; |
| 246871 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246833 | 246872 | return; |
| 246834 | 246873 | } |
| 246835 | 246874 | iOff += fts5GetVarint(&pLast->p[iOff], (u64*)&pIter->iRowid); |
| 246836 | 246875 | pIter->iLeafOffset = iOff; |
| 246837 | 246876 | |
| | @@ -246906,11 +246945,11 @@ |
| 246906 | 246945 | |
| 246907 | 246946 | iPgidx = (u32)pIter->pLeaf->szLeaf; |
| 246908 | 246947 | iPgidx += fts5GetVarint32(&a[iPgidx], iTermOff); |
| 246909 | 246948 | iOff = iTermOff; |
| 246910 | 246949 | if( iOff>n ){ |
| 246911 | | - p->rc = FTS5_CORRUPT; |
| 246950 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246912 | 246951 | return; |
| 246913 | 246952 | } |
| 246914 | 246953 | |
| 246915 | 246954 | while( 1 ){ |
| 246916 | 246955 | |
| | @@ -246949,11 +246988,11 @@ |
| 246949 | 246988 | iPgidx += fts5GetVarint32(&a[iPgidx], nKeep); |
| 246950 | 246989 | iTermOff += nKeep; |
| 246951 | 246990 | iOff = iTermOff; |
| 246952 | 246991 | |
| 246953 | 246992 | if( iOff>=n ){ |
| 246954 | | - p->rc = FTS5_CORRUPT; |
| 246993 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246955 | 246994 | return; |
| 246956 | 246995 | } |
| 246957 | 246996 | |
| 246958 | 246997 | /* Read the nKeep field of the next term. */ |
| 246959 | 246998 | fts5FastGetVarint32(a, iOff, nKeep); |
| | @@ -246971,11 +247010,11 @@ |
| 246971 | 247010 | a = pIter->pLeaf->p; |
| 246972 | 247011 | if( fts5LeafIsTermless(pIter->pLeaf)==0 ){ |
| 246973 | 247012 | iPgidx = (u32)pIter->pLeaf->szLeaf; |
| 246974 | 247013 | iPgidx += fts5GetVarint32(&pIter->pLeaf->p[iPgidx], iOff); |
| 246975 | 247014 | if( iOff<4 || (i64)iOff>=pIter->pLeaf->szLeaf ){ |
| 246976 | | - p->rc = FTS5_CORRUPT; |
| 247015 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246977 | 247016 | return; |
| 246978 | 247017 | }else{ |
| 246979 | 247018 | nKeep = 0; |
| 246980 | 247019 | iTermOff = iOff; |
| 246981 | 247020 | n = (u32)pIter->pLeaf->nn; |
| | @@ -246986,11 +247025,11 @@ |
| 246986 | 247025 | }while( 1 ); |
| 246987 | 247026 | } |
| 246988 | 247027 | |
| 246989 | 247028 | search_success: |
| 246990 | 247029 | if( (i64)iOff+nNew>n || nNew<1 ){ |
| 246991 | | - p->rc = FTS5_CORRUPT; |
| 247030 | + FTS5_CORRUPT_ITER(p, pIter); |
| 246992 | 247031 | return; |
| 246993 | 247032 | } |
| 246994 | 247033 | pIter->iLeafOffset = iOff + nNew; |
| 246995 | 247034 | pIter->iTermLeafOffset = pIter->iLeafOffset; |
| 246996 | 247035 | pIter->iTermLeafPgno = pIter->iLeafPgno; |
| | @@ -247451,11 +247490,11 @@ |
| 247451 | 247490 | int iLeafPgno |
| 247452 | 247491 | ){ |
| 247453 | 247492 | assert( iLeafPgno>pIter->iLeafPgno ); |
| 247454 | 247493 | |
| 247455 | 247494 | if( iLeafPgno>pIter->pSeg->pgnoLast ){ |
| 247456 | | - p->rc = FTS5_CORRUPT; |
| 247495 | + FTS5_CORRUPT_IDX(p); |
| 247457 | 247496 | }else{ |
| 247458 | 247497 | fts5DataRelease(pIter->pNextLeaf); |
| 247459 | 247498 | pIter->pNextLeaf = 0; |
| 247460 | 247499 | pIter->iLeafPgno = iLeafPgno-1; |
| 247461 | 247500 | |
| | @@ -247466,11 +247505,11 @@ |
| 247466 | 247505 | iOff = fts5LeafFirstRowidOff(pIter->pLeaf); |
| 247467 | 247506 | if( iOff>0 ){ |
| 247468 | 247507 | u8 *a = pIter->pLeaf->p; |
| 247469 | 247508 | int n = pIter->pLeaf->szLeaf; |
| 247470 | 247509 | if( iOff<4 || iOff>=n ){ |
| 247471 | | - p->rc = FTS5_CORRUPT; |
| 247510 | + FTS5_CORRUPT_IDX(p); |
| 247472 | 247511 | }else{ |
| 247473 | 247512 | iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid); |
| 247474 | 247513 | pIter->iLeafOffset = iOff; |
| 247475 | 247514 | fts5SegIterLoadNPos(p, pIter); |
| 247476 | 247515 | } |
| | @@ -247945,11 +247984,11 @@ |
| 247945 | 247984 | nRem -= nChunk; |
| 247946 | 247985 | fts5DataRelease(pData); |
| 247947 | 247986 | if( nRem<=0 ){ |
| 247948 | 247987 | break; |
| 247949 | 247988 | }else if( pSeg->pSeg==0 ){ |
| 247950 | | - p->rc = FTS5_CORRUPT; |
| 247989 | + FTS5_CORRUPT_IDX(p); |
| 247951 | 247990 | return; |
| 247952 | 247991 | }else{ |
| 247953 | 247992 | pgno++; |
| 247954 | 247993 | pData = fts5LeafRead(p, FTS5_SEGMENT_ROWID(pSeg->pSeg->iSegid, pgno)); |
| 247955 | 247994 | if( pData==0 ) break; |
| | @@ -249048,11 +249087,11 @@ |
| 249048 | 249087 | if( iOff>pData->szLeaf ){ |
| 249049 | 249088 | /* This can occur if the pages that the segments occupy overlap - if |
| 249050 | 249089 | ** a single page has been assigned to more than one segment. In |
| 249051 | 249090 | ** this case a prior iteration of this loop may have corrupted the |
| 249052 | 249091 | ** segment currently being trimmed. */ |
| 249053 | | - p->rc = FTS5_CORRUPT; |
| 249092 | + FTS5_CORRUPT_ROWID(p, iLeafRowid); |
| 249054 | 249093 | }else{ |
| 249055 | 249094 | fts5BufferZero(&buf); |
| 249056 | 249095 | fts5BufferGrow(&p->rc, &buf, pData->nn); |
| 249057 | 249096 | fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr); |
| 249058 | 249097 | fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n); |
| | @@ -249515,11 +249554,11 @@ |
| 249515 | 249554 | fts5DataRelease(pLeaf); |
| 249516 | 249555 | pLeaf = 0; |
| 249517 | 249556 | }else if( bDetailNone ){ |
| 249518 | 249557 | break; |
| 249519 | 249558 | }else if( iNext>=pLeaf->szLeaf || pLeaf->nn<pLeaf->szLeaf || iNext<4 ){ |
| 249520 | | - p->rc = FTS5_CORRUPT; |
| 249559 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 249521 | 249560 | break; |
| 249522 | 249561 | }else{ |
| 249523 | 249562 | int nShift = iNext - 4; |
| 249524 | 249563 | int nPg; |
| 249525 | 249564 | |
| | @@ -249535,11 +249574,11 @@ |
| 249535 | 249574 | int i1 = pLeaf->szLeaf; |
| 249536 | 249575 | int i2 = 0; |
| 249537 | 249576 | |
| 249538 | 249577 | i1 += fts5GetVarint32(&aPg[i1], iFirst); |
| 249539 | 249578 | if( iFirst<iNext ){ |
| 249540 | | - p->rc = FTS5_CORRUPT; |
| 249579 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 249541 | 249580 | break; |
| 249542 | 249581 | } |
| 249543 | 249582 | aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2); |
| 249544 | 249583 | if( aIdx==0 ) break; |
| 249545 | 249584 | i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift); |
| | @@ -249758,18 +249797,18 @@ |
| 249758 | 249797 | |
| 249759 | 249798 | nPrefix = MIN(nPrefix, nPrefix2); |
| 249760 | 249799 | nSuffix = (nPrefix2 + nSuffix2) - nPrefix; |
| 249761 | 249800 | |
| 249762 | 249801 | if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){ |
| 249763 | | - p->rc = FTS5_CORRUPT; |
| 249802 | + FTS5_CORRUPT_IDX(p); |
| 249764 | 249803 | }else{ |
| 249765 | 249804 | if( iKey!=1 ){ |
| 249766 | 249805 | iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix); |
| 249767 | 249806 | } |
| 249768 | 249807 | iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix); |
| 249769 | 249808 | if( nPrefix2>pSeg->term.n ){ |
| 249770 | | - p->rc = FTS5_CORRUPT; |
| 249809 | + FTS5_CORRUPT_IDX(p); |
| 249771 | 249810 | }else if( nPrefix2>nPrefix ){ |
| 249772 | 249811 | memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix); |
| 249773 | 249812 | iOff += (nPrefix2-nPrefix); |
| 249774 | 249813 | } |
| 249775 | 249814 | memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2); |
| | @@ -250558,11 +250597,11 @@ |
| 250558 | 250597 | fts5PrefixMergerInsertByPosition(&pHead, pSave); |
| 250559 | 250598 | pSave = pNext; |
| 250560 | 250599 | } |
| 250561 | 250600 | |
| 250562 | 250601 | if( pHead==0 || pHead->pNext==0 ){ |
| 250563 | | - p->rc = FTS5_CORRUPT; |
| 250602 | + FTS5_CORRUPT_IDX(p); |
| 250564 | 250603 | break; |
| 250565 | 250604 | } |
| 250566 | 250605 | |
| 250567 | 250606 | /* See the earlier comment in this function for an explanation of why |
| 250568 | 250607 | ** corrupt input position lists might cause the output to consume |
| | @@ -250595,11 +250634,11 @@ |
| 250595 | 250634 | |
| 250596 | 250635 | /* WRITEPOSLISTSIZE */ |
| 250597 | 250636 | assert_nc( tmp.n+nTail<=nTmp ); |
| 250598 | 250637 | assert( tmp.n+nTail<=nTmp+nMerge*10 ); |
| 250599 | 250638 | if( tmp.n+nTail>nTmp-FTS5_DATA_ZERO_PADDING ){ |
| 250600 | | - if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT; |
| 250639 | + if( p->rc==SQLITE_OK ) FTS5_CORRUPT_IDX(p); |
| 250601 | 250640 | break; |
| 250602 | 250641 | } |
| 250603 | 250642 | fts5BufferSafeAppendVarint(&out, (tmp.n+nTail) * 2); |
| 250604 | 250643 | fts5BufferSafeAppendBlob(&out, tmp.p, tmp.n); |
| 250605 | 250644 | if( nTail>0 ){ |
| | @@ -252724,18 +252763,21 @@ |
| 252724 | 252763 | /* Now check that the iter.nEmpty leaves following the current leaf |
| 252725 | 252764 | ** (a) exist and (b) contain no terms. */ |
| 252726 | 252765 | for(i=iFirst; p->rc==SQLITE_OK && i<=iLast; i++){ |
| 252727 | 252766 | Fts5Data *pLeaf = fts5DataRead(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); |
| 252728 | 252767 | if( pLeaf ){ |
| 252729 | | - if( !fts5LeafIsTermless(pLeaf) ) p->rc = FTS5_CORRUPT; |
| 252730 | | - if( i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf) ) p->rc = FTS5_CORRUPT; |
| 252768 | + if( !fts5LeafIsTermless(pLeaf) |
| 252769 | + || (i>=iNoRowid && 0!=fts5LeafFirstRowidOff(pLeaf)) |
| 252770 | + ){ |
| 252771 | + FTS5_CORRUPT_ROWID(p, FTS5_SEGMENT_ROWID(pSeg->iSegid, i)); |
| 252772 | + } |
| 252731 | 252773 | } |
| 252732 | 252774 | fts5DataRelease(pLeaf); |
| 252733 | 252775 | } |
| 252734 | 252776 | } |
| 252735 | 252777 | |
| 252736 | | -static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){ |
| 252778 | +static void fts5IntegrityCheckPgidx(Fts5Index *p, i64 iRowid, Fts5Data *pLeaf){ |
| 252737 | 252779 | i64 iTermOff = 0; |
| 252738 | 252780 | int ii; |
| 252739 | 252781 | |
| 252740 | 252782 | Fts5Buffer buf1 = {0,0,0}; |
| 252741 | 252783 | Fts5Buffer buf2 = {0,0,0}; |
| | @@ -252749,33 +252791,33 @@ |
| 252749 | 252791 | ii += fts5GetVarint32(&pLeaf->p[ii], nIncr); |
| 252750 | 252792 | iTermOff += nIncr; |
| 252751 | 252793 | iOff = iTermOff; |
| 252752 | 252794 | |
| 252753 | 252795 | if( iOff>=pLeaf->szLeaf ){ |
| 252754 | | - p->rc = FTS5_CORRUPT; |
| 252796 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 252755 | 252797 | }else if( iTermOff==nIncr ){ |
| 252756 | 252798 | int nByte; |
| 252757 | 252799 | iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); |
| 252758 | 252800 | if( (iOff+nByte)>pLeaf->szLeaf ){ |
| 252759 | | - p->rc = FTS5_CORRUPT; |
| 252801 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 252760 | 252802 | }else{ |
| 252761 | 252803 | fts5BufferSet(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); |
| 252762 | 252804 | } |
| 252763 | 252805 | }else{ |
| 252764 | 252806 | int nKeep, nByte; |
| 252765 | 252807 | iOff += fts5GetVarint32(&pLeaf->p[iOff], nKeep); |
| 252766 | 252808 | iOff += fts5GetVarint32(&pLeaf->p[iOff], nByte); |
| 252767 | 252809 | if( nKeep>buf1.n || (iOff+nByte)>pLeaf->szLeaf ){ |
| 252768 | | - p->rc = FTS5_CORRUPT; |
| 252810 | + FTS5_CORRUPT_ROWID(p, iRowid); |
| 252769 | 252811 | }else{ |
| 252770 | 252812 | buf1.n = nKeep; |
| 252771 | 252813 | fts5BufferAppendBlob(&p->rc, &buf1, nByte, &pLeaf->p[iOff]); |
| 252772 | 252814 | } |
| 252773 | 252815 | |
| 252774 | 252816 | if( p->rc==SQLITE_OK ){ |
| 252775 | 252817 | res = fts5BufferCompare(&buf1, &buf2); |
| 252776 | | - if( res<=0 ) p->rc = FTS5_CORRUPT; |
| 252818 | + if( res<=0 ) FTS5_CORRUPT_ROWID(p, iRowid); |
| 252777 | 252819 | } |
| 252778 | 252820 | } |
| 252779 | 252821 | fts5BufferSet(&p->rc, &buf2, buf1.n, buf1.p); |
| 252780 | 252822 | } |
| 252781 | 252823 | |
| | @@ -252832,11 +252874,11 @@ |
| 252832 | 252874 | ){ |
| 252833 | 252875 | /* special case - the very first page in a segment keeps its %_idx |
| 252834 | 252876 | ** entry even if all the terms are removed from it by secure-delete |
| 252835 | 252877 | ** operations. */ |
| 252836 | 252878 | }else{ |
| 252837 | | - p->rc = FTS5_CORRUPT; |
| 252879 | + FTS5_CORRUPT_ROWID(p, iRow); |
| 252838 | 252880 | } |
| 252839 | 252881 | |
| 252840 | 252882 | }else{ |
| 252841 | 252883 | int iOff; /* Offset of first term on leaf */ |
| 252842 | 252884 | int iRowidOff; /* Offset of first rowid on leaf */ |
| | @@ -252844,19 +252886,19 @@ |
| 252844 | 252886 | int res; /* Comparison of term and split-key */ |
| 252845 | 252887 | |
| 252846 | 252888 | iOff = fts5LeafFirstTermOff(pLeaf); |
| 252847 | 252889 | iRowidOff = fts5LeafFirstRowidOff(pLeaf); |
| 252848 | 252890 | if( iRowidOff>=iOff || iOff>=pLeaf->szLeaf ){ |
| 252849 | | - p->rc = FTS5_CORRUPT; |
| 252891 | + FTS5_CORRUPT_ROWID(p, iRow); |
| 252850 | 252892 | }else{ |
| 252851 | 252893 | iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); |
| 252852 | 252894 | res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); |
| 252853 | 252895 | if( res==0 ) res = nTerm - nIdxTerm; |
| 252854 | | - if( res<0 ) p->rc = FTS5_CORRUPT; |
| 252896 | + if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow); |
| 252855 | 252897 | } |
| 252856 | 252898 | |
| 252857 | | - fts5IntegrityCheckPgidx(p, pLeaf); |
| 252899 | + fts5IntegrityCheckPgidx(p, iRow, pLeaf); |
| 252858 | 252900 | } |
| 252859 | 252901 | fts5DataRelease(pLeaf); |
| 252860 | 252902 | if( p->rc ) break; |
| 252861 | 252903 | |
| 252862 | 252904 | /* Now check that the iter.nEmpty leaves following the current leaf |
| | @@ -252882,11 +252924,11 @@ |
| 252882 | 252924 | /* Check any rowid-less pages that occur before the current leaf. */ |
| 252883 | 252925 | for(iPg=iPrevLeaf+1; iPg<fts5DlidxIterPgno(pDlidx); iPg++){ |
| 252884 | 252926 | iKey = FTS5_SEGMENT_ROWID(iSegid, iPg); |
| 252885 | 252927 | pLeaf = fts5DataRead(p, iKey); |
| 252886 | 252928 | if( pLeaf ){ |
| 252887 | | - if( fts5LeafFirstRowidOff(pLeaf)!=0 ) p->rc = FTS5_CORRUPT; |
| 252929 | + if( fts5LeafFirstRowidOff(pLeaf)!=0 ) FTS5_CORRUPT_ROWID(p, iKey); |
| 252888 | 252930 | fts5DataRelease(pLeaf); |
| 252889 | 252931 | } |
| 252890 | 252932 | } |
| 252891 | 252933 | iPrevLeaf = fts5DlidxIterPgno(pDlidx); |
| 252892 | 252934 | |
| | @@ -252897,16 +252939,16 @@ |
| 252897 | 252939 | if( pLeaf ){ |
| 252898 | 252940 | i64 iRowid; |
| 252899 | 252941 | int iRowidOff = fts5LeafFirstRowidOff(pLeaf); |
| 252900 | 252942 | ASSERT_SZLEAF_OK(pLeaf); |
| 252901 | 252943 | if( iRowidOff>=pLeaf->szLeaf ){ |
| 252902 | | - p->rc = FTS5_CORRUPT; |
| 252944 | + FTS5_CORRUPT_ROWID(p, iKey); |
| 252903 | 252945 | }else if( bSecureDelete==0 || iRowidOff>0 ){ |
| 252904 | 252946 | i64 iDlRowid = fts5DlidxIterRowid(pDlidx); |
| 252905 | 252947 | fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid); |
| 252906 | 252948 | if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){ |
| 252907 | | - p->rc = FTS5_CORRUPT; |
| 252949 | + FTS5_CORRUPT_ROWID(p, iKey); |
| 252908 | 252950 | } |
| 252909 | 252951 | } |
| 252910 | 252952 | fts5DataRelease(pLeaf); |
| 252911 | 252953 | } |
| 252912 | 252954 | } |
| | @@ -253017,11 +253059,16 @@ |
| 253017 | 253059 | } |
| 253018 | 253060 | } |
| 253019 | 253061 | fts5TestTerm(p, &term, 0, 0, cksum2, &cksum3); |
| 253020 | 253062 | |
| 253021 | 253063 | fts5MultiIterFree(pIter); |
| 253022 | | - if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ) p->rc = FTS5_CORRUPT; |
| 253064 | + if( p->rc==SQLITE_OK && bUseCksum && cksum!=cksum2 ){ |
| 253065 | + p->rc = FTS5_CORRUPT; |
| 253066 | + sqlite3Fts5ConfigErrmsg(p->pConfig, |
| 253067 | + "fts5: checksum mismatch for table \"%s\"", p->pConfig->zName |
| 253068 | + ); |
| 253069 | + } |
| 253023 | 253070 | |
| 253024 | 253071 | fts5StructureRelease(pStruct); |
| 253025 | 253072 | #ifdef SQLITE_DEBUG |
| 253026 | 253073 | fts5BufferFree(&term); |
| 253027 | 253074 | #endif |
| | @@ -257433,11 +257480,11 @@ |
| 257433 | 257480 | int nArg, /* Number of args */ |
| 257434 | 257481 | sqlite3_value **apUnused /* Function arguments */ |
| 257435 | 257482 | ){ |
| 257436 | 257483 | assert( nArg==0 ); |
| 257437 | 257484 | UNUSED_PARAM2(nArg, apUnused); |
| 257438 | | - sqlite3_result_text(pCtx, "fts5: 2025-06-23 16:51:33 cf61cd359e666c66b6bba4407a653c799f7f07e1f5ee6b837ad467029c461a6a", -1, SQLITE_TRANSIENT); |
| 257485 | + sqlite3_result_text(pCtx, "fts5: 2025-06-24 15:58:32 6a5701e6c7be25cba93e55438f950966e1dacb32eb2b23a8acc8ac53da6f0a85", -1, SQLITE_TRANSIENT); |
| 257439 | 257486 | } |
| 257440 | 257487 | |
| 257441 | 257488 | /* |
| 257442 | 257489 | ** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 257443 | 257490 | ** |
| | @@ -257556,12 +257603,13 @@ |
| 257556 | 257603 | }else{ |
| 257557 | 257604 | *pzErr = sqlite3_mprintf("unable to validate the inverted index for" |
| 257558 | 257605 | " FTS5 table %s.%s: %s", |
| 257559 | 257606 | zSchema, zTabname, sqlite3_errstr(rc)); |
| 257560 | 257607 | } |
| 257608 | + }else if( (rc&0xff)==SQLITE_CORRUPT ){ |
| 257609 | + rc = SQLITE_OK; |
| 257561 | 257610 | } |
| 257562 | | - |
| 257563 | 257611 | sqlite3Fts5IndexCloseReader(pTab->p.pIndex); |
| 257564 | 257612 | pTab->p.pConfig->pzErrmsg = 0; |
| 257565 | 257613 | |
| 257566 | 257614 | return rc; |
| 257567 | 257615 | } |
| 257568 | 257616 | |