Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(666)

Unified Diff: third_party/sqlite/fts3.patch

Issue 6990047: Import SQLite 3.7.6.3. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/sqlite/attach-integer.patch ('k') | third_party/sqlite/icu-regexp.patch » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/sqlite/fts3.patch
diff --git a/third_party/sqlite/fts3.patch b/third_party/sqlite/fts3.patch
index 622626a3aa09bd35dd1fe2830e31fc750323a905..07fdb1a6afcb12b295146b5560dd8af558cd8f85 100644
--- a/third_party/sqlite/fts3.patch
+++ b/third_party/sqlite/fts3.patch
@@ -1,8 +1,8 @@
-Index: ext/fts3/fts3.c
-===================================================================
---- ext/fts3/fts3.c (revision 48811)
-+++ ext/fts3/fts3.c (working copy)
-@@ -271,6 +271,7 @@
+diff --git ext/fts3/fts3.c ext/fts3/fts3.c
+index 20da051..71e22ae 100644
+--- ext/fts3/fts3.c
++++ ext/fts3/fts3.c
+@@ -291,6 +291,7 @@
** deletions and duplications. This would basically be a forced merge
** into a single segment.
*/
@@ -10,1884 +10,22 @@ Index: ext/fts3/fts3.c
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)
-@@ -313,6 +314,16 @@
- # define FTSTRACE(A)
- #endif
-
-+#if 0
-+/* Useful to set breakpoints. See main.c sqlite3Corrupt(). */
-+static int fts3Corrupt(void){
-+ return SQLITE_CORRUPT;
-+}
-+# define SQLITE_CORRUPT_BKPT fts3Corrupt()
-+#else
-+# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
-+#endif
-+
- /* It is not safe to call isspace(), tolower(), or isalnum() on
- ** hi-bit-set characters. This is the same solution used in the
- ** tokenizer.
-@@ -401,30 +412,41 @@
- /* Read a 64-bit variable-length integer from memory starting at p[0].
- * Return the number of bytes read, or 0 on error.
- * The value is stored in *v. */
--static int fts3GetVarint(const char *p, sqlite_int64 *v){
-+static int fts3GetVarintSafe(const char *p, sqlite_int64 *v, int max){
- const unsigned char *q = (const unsigned char *) p;
- sqlite_uint64 x = 0, y = 1;
-- while( (*q & 0x80) == 0x80 ){
-+ if( max>VARINT_MAX ) max = VARINT_MAX;
-+ while( max && (*q & 0x80) == 0x80 ){
-+ max--;
- x += y * (*q++ & 0x7f);
- y <<= 7;
-- if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */
-- assert( 0 );
-- return 0;
-- }
- }
-+ if( !max ){
-+ assert( 0 );
-+ return 0; /* tried to read too much; bad data */
-+ }
- x += y * (*q++);
- *v = (sqlite_int64) x;
- return (int) (q - (unsigned char *)p);
- }
-
--static int fts3GetVarint32(const char *p, int *pi){
-+static int fts3GetVarint(const char *p, sqlite_int64 *v){
-+ return fts3GetVarintSafe(p, v, VARINT_MAX);
-+}
-+
-+static int fts3GetVarint32Safe(const char *p, int *pi, int max){
- sqlite_int64 i;
-- int ret = fts3GetVarint(p, &i);
-+ int ret = fts3GetVarintSafe(p, &i, max);
-+ if( !ret ) return ret;
- *pi = (int) i;
- assert( *pi==i );
- return ret;
- }
-
-+static int fts3GetVarint32(const char* p, int *pi){
-+ return fts3GetVarint32Safe(p, pi, VARINT_MAX);
-+}
-+
- /*******************************************************************/
- /* DataBuffer is used to collect data into a buffer in piecemeal
- ** fashion. It implements the usual distinction between amount of
-@@ -593,7 +615,7 @@
-
- static int dlrAtEnd(DLReader *pReader){
- assert( pReader->nData>=0 );
-- return pReader->nData==0;
-+ return pReader->nData<=0;
- }
- static sqlite_int64 dlrDocid(DLReader *pReader){
- assert( !dlrAtEnd(pReader) );
-@@ -617,7 +639,8 @@
- */
- static const char *dlrPosData(DLReader *pReader){
- sqlite_int64 iDummy;
-- int n = fts3GetVarint(pReader->pData, &iDummy);
-+ int n = fts3GetVarintSafe(pReader->pData, &iDummy, pReader->nElement);
-+ if( !n ) return NULL;
- assert( !dlrAtEnd(pReader) );
- return pReader->pData+n;
- }
-@@ -627,7 +650,7 @@
- assert( !dlrAtEnd(pReader) );
- return pReader->nElement-n;
- }
--static void dlrStep(DLReader *pReader){
-+static int dlrStep(DLReader *pReader){
- assert( !dlrAtEnd(pReader) );
-
- /* Skip past current doclist element. */
-@@ -636,32 +659,44 @@
- pReader->nData -= pReader->nElement;
-
- /* If there is more data, read the next doclist element. */
-- if( pReader->nData!=0 ){
-+ if( pReader->nData>0 ){
- sqlite_int64 iDocidDelta;
-- int iDummy, n = fts3GetVarint(pReader->pData, &iDocidDelta);
-+ int nTotal = 0;
-+ int iDummy, n = fts3GetVarintSafe(pReader->pData, &iDocidDelta, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- pReader->iDocid += iDocidDelta;
- if( pReader->iType>=DL_POSITIONS ){
-- assert( n<pReader->nData );
- while( 1 ){
-- n += fts3GetVarint32(pReader->pData+n, &iDummy);
-- assert( n<=pReader->nData );
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- if( iDummy==POS_END ) break;
- if( iDummy==POS_COLUMN ){
-- n += fts3GetVarint32(pReader->pData+n, &iDummy);
-- assert( n<pReader->nData );
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- }else if( pReader->iType==DL_POSITIONS_OFFSETS ){
-- n += fts3GetVarint32(pReader->pData+n, &iDummy);
-- n += fts3GetVarint32(pReader->pData+n, &iDummy);
-- assert( n<pReader->nData );
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &iDummy, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- }
- }
- }
-- pReader->nElement = n;
-+ pReader->nElement = nTotal;
- assert( pReader->nElement<=pReader->nData );
- }
-+ return SQLITE_OK;
- }
--static void dlrInit(DLReader *pReader, DocListType iType,
-- const char *pData, int nData){
-+static void dlrDestroy(DLReader *pReader){
-+ SCRAMBLE(pReader);
-+}
-+static int dlrInit(DLReader *pReader, DocListType iType,
-+ const char *pData, int nData){
-+ int rc;
- assert( pData!=NULL && nData!=0 );
- pReader->iType = iType;
- pReader->pData = pData;
-@@ -670,11 +705,10 @@
- pReader->iDocid = 0;
-
- /* Load the first element's data. There must be a first element. */
-- dlrStep(pReader);
-+ rc = dlrStep(pReader);
-+ if( rc!=SQLITE_OK ) dlrDestroy(pReader);
-+ return rc;
- }
--static void dlrDestroy(DLReader *pReader){
-- SCRAMBLE(pReader);
--}
-
- #ifndef NDEBUG
- /* Verify that the doclist can be validly decoded. Also returns the
-@@ -760,9 +794,9 @@
- /* TODO(shess) This has become just a helper for docListMerge.
- ** Consider a refactor to make this cleaner.
- */
--static void dlwAppend(DLWriter *pWriter,
-- const char *pData, int nData,
-- sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){
-+static int dlwAppend(DLWriter *pWriter,
-+ const char *pData, int nData,
-+ sqlite_int64 iFirstDocid, sqlite_int64 iLastDocid){
- sqlite_int64 iDocid = 0;
- char c[VARINT_MAX];
- int nFirstOld, nFirstNew; /* Old and new varint len of first docid. */
-@@ -771,7 +805,8 @@
- #endif
-
- /* Recode the initial docid as delta from iPrevDocid. */
-- nFirstOld = fts3GetVarint(pData, &iDocid);
-+ nFirstOld = fts3GetVarintSafe(pData, &iDocid, nData);
-+ if( !nFirstOld ) return SQLITE_CORRUPT_BKPT;
- assert( nFirstOld<nData || (nFirstOld==nData && pWriter->iType==DL_DOCIDS) );
- nFirstNew = fts3PutVarint(c, iFirstDocid-pWriter->iPrevDocid);
-
-@@ -792,10 +827,11 @@
- dataBufferAppend(pWriter->b, c, nFirstNew);
- }
- pWriter->iPrevDocid = iLastDocid;
-+ return SQLITE_OK;
- }
--static void dlwCopy(DLWriter *pWriter, DLReader *pReader){
-- dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader),
-- dlrDocid(pReader), dlrDocid(pReader));
-+static int dlwCopy(DLWriter *pWriter, DLReader *pReader){
-+ return dlwAppend(pWriter, dlrDocData(pReader), dlrDocDataBytes(pReader),
-+ dlrDocid(pReader), dlrDocid(pReader));
- }
- static void dlwAdd(DLWriter *pWriter, sqlite_int64 iDocid){
- char c[VARINT_MAX];
-@@ -856,45 +892,61 @@
- assert( !plrAtEnd(pReader) );
- return pReader->iEndOffset;
- }
--static void plrStep(PLReader *pReader){
-- int i, n;
-+static int plrStep(PLReader *pReader){
-+ int i, n, nTotal = 0;
-
- assert( !plrAtEnd(pReader) );
-
-- if( pReader->nData==0 ){
-+ if( pReader->nData<=0 ){
- pReader->pData = NULL;
-- return;
-+ return SQLITE_OK;
- }
-
-- n = fts3GetVarint32(pReader->pData, &i);
-+ n = fts3GetVarint32Safe(pReader->pData, &i, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- if( i==POS_COLUMN ){
-- n += fts3GetVarint32(pReader->pData+n, &pReader->iColumn);
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &pReader->iColumn, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- pReader->iPosition = 0;
- pReader->iStartOffset = 0;
-- n += fts3GetVarint32(pReader->pData+n, &i);
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- }
- /* Should never see adjacent column changes. */
- assert( i!=POS_COLUMN );
-
- if( i==POS_END ){
-+ assert( nTotal<=pReader->nData );
- pReader->nData = 0;
- pReader->pData = NULL;
-- return;
-+ return SQLITE_OK;
- }
-
- pReader->iPosition += i-POS_BASE;
- if( pReader->iType==DL_POSITIONS_OFFSETS ){
-- n += fts3GetVarint32(pReader->pData+n, &i);
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- pReader->iStartOffset += i;
-- n += fts3GetVarint32(pReader->pData+n, &i);
-+ n = fts3GetVarint32Safe(pReader->pData+nTotal, &i, pReader->nData-nTotal);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ nTotal += n;
- pReader->iEndOffset = pReader->iStartOffset+i;
- }
-- assert( n<=pReader->nData );
-- pReader->pData += n;
-- pReader->nData -= n;
-+ assert( nTotal<=pReader->nData );
-+ pReader->pData += nTotal;
-+ pReader->nData -= nTotal;
-+ return SQLITE_OK;
- }
-
--static void plrInit(PLReader *pReader, DLReader *pDLReader){
-+static void plrDestroy(PLReader *pReader){
-+ SCRAMBLE(pReader);
-+}
-+static int plrInit(PLReader *pReader, DLReader *pDLReader){
-+ int rc;
- pReader->pData = dlrPosData(pDLReader);
- pReader->nData = dlrPosDataLen(pDLReader);
- pReader->iType = pDLReader->iType;
-@@ -902,11 +954,10 @@
- pReader->iPosition = 0;
- pReader->iStartOffset = 0;
- pReader->iEndOffset = 0;
-- plrStep(pReader);
-+ rc = plrStep(pReader);
-+ if( rc!=SQLITE_OK ) plrDestroy(pReader);
-+ return rc;
- }
--static void plrDestroy(PLReader *pReader){
-- SCRAMBLE(pReader);
--}
-
- /*******************************************************************/
- /* PLWriter is used in constructing a document's position list. As a
-@@ -1091,14 +1142,16 @@
- ** deletion will be trimmed, and will thus not effect a deletion
- ** during the merge.
- */
--static void docListTrim(DocListType iType, const char *pData, int nData,
-- int iColumn, DocListType iOutType, DataBuffer *out){
-+static int docListTrim(DocListType iType, const char *pData, int nData,
-+ int iColumn, DocListType iOutType, DataBuffer *out){
- DLReader dlReader;
- DLWriter dlWriter;
-+ int rc;
-
- assert( iOutType<=iType );
-
-- dlrInit(&dlReader, iType, pData, nData);
-+ rc = dlrInit(&dlReader, iType, pData, nData);
-+ if( rc!=SQLITE_OK ) return rc;
- dlwInit(&dlWriter, iOutType, out);
-
- while( !dlrAtEnd(&dlReader) ){
-@@ -1106,7 +1159,8 @@
- PLWriter plWriter;
- int match = 0;
-
-- plrInit(&plReader, &dlReader);
-+ rc = plrInit(&plReader, &dlReader);
-+ if( rc!=SQLITE_OK ) break;
-
- while( !plrAtEnd(&plReader) ){
- if( iColumn==-1 || plrColumn(&plReader)==iColumn ){
-@@ -1117,7 +1171,11 @@
- plwAdd(&plWriter, plrColumn(&plReader), plrPosition(&plReader),
- plrStartOffset(&plReader), plrEndOffset(&plReader));
- }
-- plrStep(&plReader);
-+ rc = plrStep(&plReader);
-+ if( rc!=SQLITE_OK ){
-+ plrDestroy(&plReader);
-+ goto err;
-+ }
- }
- if( match ){
- plwTerminate(&plWriter);
-@@ -1125,10 +1183,13 @@
- }
-
- plrDestroy(&plReader);
-- dlrStep(&dlReader);
-+ rc = dlrStep(&dlReader);
-+ if( rc!=SQLITE_OK ) break;
- }
-+err:
- dlwDestroy(&dlWriter);
- dlrDestroy(&dlReader);
-+ return rc;
- }
-
- /* Used by docListMerge() to keep doclists in the ascending order by
-@@ -1185,19 +1246,20 @@
- /* TODO(shess) nReaders must be <= MERGE_COUNT. This should probably
- ** be fixed.
- */
--static void docListMerge(DataBuffer *out,
-- DLReader *pReaders, int nReaders){
-+static int docListMerge(DataBuffer *out,
-+ DLReader *pReaders, int nReaders){
- OrderedDLReader readers[MERGE_COUNT];
- DLWriter writer;
- int i, n;
- const char *pStart = 0;
- int nStart = 0;
- sqlite_int64 iFirstDocid = 0, iLastDocid = 0;
-+ int rc = SQLITE_OK;
-
- assert( nReaders>0 );
- if( nReaders==1 ){
- dataBufferAppend(out, dlrDocData(pReaders), dlrAllDataBytes(pReaders));
-- return;
-+ return SQLITE_OK;
- }
-
- assert( nReaders<=MERGE_COUNT );
-@@ -1230,20 +1292,23 @@
- nStart += dlrDocDataBytes(readers[0].pReader);
- }else{
- if( pStart!=0 ){
-- dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid);
-+ rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid);
-+ if( rc!=SQLITE_OK ) goto err;
- }
- pStart = dlrDocData(readers[0].pReader);
- nStart = dlrDocDataBytes(readers[0].pReader);
- iFirstDocid = iDocid;
- }
- iLastDocid = iDocid;
-- dlrStep(readers[0].pReader);
-+ rc = dlrStep(readers[0].pReader);
-+ if( rc!= SQLITE_OK ) goto err;
-
- /* Drop all of the older elements with the same docid. */
- for(i=1; i<nReaders &&
- !dlrAtEnd(readers[i].pReader) &&
- dlrDocid(readers[i].pReader)==iDocid; i++){
-- dlrStep(readers[i].pReader);
-+ rc = dlrStep(readers[i].pReader);
-+ if( rc!=SQLITE_OK ) goto err;
- }
-
- /* Get the readers back into order. */
-@@ -1253,8 +1318,10 @@
- }
-
- /* Copy over any remaining elements. */
-- if( nStart>0 ) dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid);
-+ if( nStart>0 ) rc = dlwAppend(&writer, pStart, nStart, iFirstDocid, iLastDocid);
-+err:
- dlwDestroy(&writer);
-+ return rc;
- }
-
- /* Helper function for posListUnion(). Compares the current position
-@@ -1290,30 +1357,40 @@
- ** work with any doclist type, though both inputs and the output
- ** should be the same type.
- */
--static void posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){
-+static int posListUnion(DLReader *pLeft, DLReader *pRight, DLWriter *pOut){
- PLReader left, right;
- PLWriter writer;
-+ int rc;
-
- assert( dlrDocid(pLeft)==dlrDocid(pRight) );
- assert( pLeft->iType==pRight->iType );
- assert( pLeft->iType==pOut->iType );
-
-- plrInit(&left, pLeft);
-- plrInit(&right, pRight);
-+ rc = plrInit(&left, pLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = plrInit(&right, pRight);
-+ if( rc!=SQLITE_OK ){
-+ plrDestroy(&left);
-+ return rc;
-+ }
- plwInit(&writer, pOut, dlrDocid(pLeft));
-
- while( !plrAtEnd(&left) || !plrAtEnd(&right) ){
- int c = posListCmp(&left, &right);
- if( c<0 ){
- plwCopy(&writer, &left);
-- plrStep(&left);
-+ rc = plrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( c>0 ){
- plwCopy(&writer, &right);
-- plrStep(&right);
-+ rc = plrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
- plwCopy(&writer, &left);
-- plrStep(&left);
-- plrStep(&right);
-+ rc = plrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = plrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
-
-@@ -1321,56 +1398,75 @@
- plwDestroy(&writer);
- plrDestroy(&left);
- plrDestroy(&right);
-+ return rc;
- }
-
- /* Write the union of doclists in pLeft and pRight to pOut. For
- ** docids in common between the inputs, the union of the position
- ** lists is written. Inputs and outputs are always type DL_DEFAULT.
- */
--static void docListUnion(
-+static int docListUnion(
- const char *pLeft, int nLeft,
- const char *pRight, int nRight,
- DataBuffer *pOut /* Write the combined doclist here */
- ){
- DLReader left, right;
- DLWriter writer;
-+ int rc;
-
- if( nLeft==0 ){
- if( nRight!=0) dataBufferAppend(pOut, pRight, nRight);
-- return;
-+ return SQLITE_OK;
- }
- if( nRight==0 ){
- dataBufferAppend(pOut, pLeft, nLeft);
-- return;
-+ return SQLITE_OK;
- }
-
-- dlrInit(&left, DL_DEFAULT, pLeft, nLeft);
-- dlrInit(&right, DL_DEFAULT, pRight, nRight);
-+ rc = dlrInit(&left, DL_DEFAULT, pLeft, nLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrInit(&right, DL_DEFAULT, pRight, nRight);
-+ if( rc!=SQLITE_OK){
-+ dlrDestroy(&left);
-+ return rc;
-+ }
- dlwInit(&writer, DL_DEFAULT, pOut);
-
- while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){
- if( dlrAtEnd(&right) ){
-- dlwCopy(&writer, &left);
-- dlrStep(&left);
-+ rc = dlwCopy(&writer, &left);
-+ if( rc!=SQLITE_OK) break;
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK) break;
- }else if( dlrAtEnd(&left) ){
-- dlwCopy(&writer, &right);
-- dlrStep(&right);
-+ rc = dlwCopy(&writer, &right);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrDocid(&left)<dlrDocid(&right) ){
-- dlwCopy(&writer, &left);
-- dlrStep(&left);
-+ rc = dlwCopy(&writer, &left);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrDocid(&left)>dlrDocid(&right) ){
-- dlwCopy(&writer, &right);
-- dlrStep(&right);
-+ rc = dlwCopy(&writer, &right);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
-- posListUnion(&left, &right, &writer);
-- dlrStep(&left);
-- dlrStep(&right);
-+ rc = posListUnion(&left, &right, &writer);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
-
- dlrDestroy(&left);
- dlrDestroy(&right);
- dlwDestroy(&writer);
-+ return rc;
- }
-
- /*
-@@ -1394,7 +1490,7 @@
- ** from pLeft instead of pRight. In the example above, the positions "5"
- ** and "20" would be added instead of "6" and "21".
- */
--static void posListPhraseMerge(
-+static int posListPhraseMerge(
- DLReader *pLeft,
- DLReader *pRight,
- int nNear,
-@@ -1404,20 +1500,29 @@
- PLReader left, right;
- PLWriter writer;
- int match = 0;
-+ int rc;
-
- assert( dlrDocid(pLeft)==dlrDocid(pRight) );
- assert( pOut->iType!=DL_POSITIONS_OFFSETS );
-
-- plrInit(&left, pLeft);
-- plrInit(&right, pRight);
-+ rc = plrInit(&left, pLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = plrInit(&right, pRight);
-+ if( rc!=SQLITE_OK ){
-+ plrDestroy(&left);
-+ return rc;
-+ }
-
- while( !plrAtEnd(&left) && !plrAtEnd(&right) ){
- if( plrColumn(&left)<plrColumn(&right) ){
-- plrStep(&left);
-+ rc = plrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( plrColumn(&left)>plrColumn(&right) ){
-- plrStep(&right);
-+ rc = plrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else if( plrPosition(&left)>=plrPosition(&right) ){
-- plrStep(&right);
-+ rc = plrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
- if( (plrPosition(&right)-plrPosition(&left))<=(nNear+1) ){
- if( !match ){
-@@ -1429,9 +1534,11 @@
- }else{
- plwAdd(&writer, plrColumn(&left), plrPosition(&left), 0, 0);
- }
-- plrStep(&right);
-+ rc = plrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
-- plrStep(&left);
-+ rc = plrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
- }
-@@ -1443,6 +1550,7 @@
-
- plrDestroy(&left);
- plrDestroy(&right);
-+ return rc;
- }
-
- /*
-@@ -1496,7 +1604,7 @@
- ** iType controls the type of data written to pOut. If iType is
- ** DL_POSITIONS, the positions are those from pRight.
- */
--static void docListPhraseMerge(
-+static int docListPhraseMerge(
- const char *pLeft, int nLeft,
- const char *pRight, int nRight,
- int nNear, /* 0 for a phrase merge, non-zero for a NEAR merge */
-@@ -1506,43 +1614,63 @@
- ){
- DLReader left, right;
- DLWriter writer;
-+ int rc;
-
-- if( nLeft==0 || nRight==0 ) return;
-+ /* These two buffers are used in the 'while', but are declared here
-+ ** to simplify error-handling.
-+ */
-+ DataBuffer one = {0, 0, 0};
-+ DataBuffer two = {0, 0, 0};
-
-+ if( nLeft==0 || nRight==0 ) return SQLITE_OK;
-+
- assert( iType!=DL_POSITIONS_OFFSETS );
-
-- dlrInit(&left, DL_POSITIONS, pLeft, nLeft);
-- dlrInit(&right, DL_POSITIONS, pRight, nRight);
-+ rc = dlrInit(&left, DL_POSITIONS, pLeft, nLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrInit(&right, DL_POSITIONS, pRight, nRight);
-+ if( rc!=SQLITE_OK ){
-+ dlrDestroy(&left);
-+ return rc;
-+ }
- dlwInit(&writer, iType, pOut);
-
- while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){
- if( dlrDocid(&left)<dlrDocid(&right) ){
-- dlrStep(&left);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) goto err;
- }else if( dlrDocid(&right)<dlrDocid(&left) ){
-- dlrStep(&right);
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) goto err;
- }else{
- if( nNear==0 ){
-- posListPhraseMerge(&left, &right, 0, 0, &writer);
-+ rc = posListPhraseMerge(&left, &right, 0, 0, &writer);
-+ if( rc!=SQLITE_OK ) goto err;
- }else{
- /* This case occurs when two terms (simple terms or phrases) are
- * connected by a NEAR operator, span (nNear+1). i.e.
- *
- * '"terrible company" NEAR widget'
- */
-- DataBuffer one = {0, 0, 0};
-- DataBuffer two = {0, 0, 0};
--
- DLWriter dlwriter2;
-- DLReader dr1 = {0, 0, 0, 0, 0};
-+ DLReader dr1 = {0, 0, 0, 0, 0};
- DLReader dr2 = {0, 0, 0, 0, 0};
-
- dlwInit(&dlwriter2, iType, &one);
-- posListPhraseMerge(&right, &left, nNear-3+nPhrase, 1, &dlwriter2);
-+ rc = posListPhraseMerge(&right, &left, nNear-3+nPhrase, 1, &dlwriter2);
-+ if( rc!=SQLITE_OK ) goto err;
- dlwInit(&dlwriter2, iType, &two);
-- posListPhraseMerge(&left, &right, nNear-1, 0, &dlwriter2);
-+ rc = posListPhraseMerge(&left, &right, nNear-1, 0, &dlwriter2);
-+ if( rc!=SQLITE_OK ) goto err;
-
-- if( one.nData) dlrInit(&dr1, iType, one.pData, one.nData);
-- if( two.nData) dlrInit(&dr2, iType, two.pData, two.nData);
-+ if( one.nData){
-+ rc = dlrInit(&dr1, iType, one.pData, one.nData);
-+ if( rc!=SQLITE_OK ) goto err;
-+ }
-+ if( two.nData){
-+ rc = dlrInit(&dr2, iType, two.pData, two.nData);
-+ if( rc!=SQLITE_OK ) goto err;
-+ }
-
- if( !dlrAtEnd(&dr1) || !dlrAtEnd(&dr2) ){
- PLReader pr1 = {0};
-@@ -1551,161 +1679,211 @@
- PLWriter plwriter;
- plwInit(&plwriter, &writer, dlrDocid(dlrAtEnd(&dr1)?&dr2:&dr1));
-
-- if( one.nData ) plrInit(&pr1, &dr1);
-- if( two.nData ) plrInit(&pr2, &dr2);
-+ if( one.nData ){
-+ rc = plrInit(&pr1, &dr1);
-+ if( rc!=SQLITE_OK ) goto err;
-+ }
-+ if( two.nData ){
-+ rc = plrInit(&pr2, &dr2);
-+ if( rc!=SQLITE_OK ) goto err;
-+ }
- while( !plrAtEnd(&pr1) || !plrAtEnd(&pr2) ){
- int iCompare = plrCompare(&pr1, &pr2);
- switch( iCompare ){
- case -1:
- plwCopy(&plwriter, &pr1);
-- plrStep(&pr1);
-+ rc = plrStep(&pr1);
-+ if( rc!=SQLITE_OK ) goto err;
- break;
- case 1:
- plwCopy(&plwriter, &pr2);
-- plrStep(&pr2);
-+ rc = plrStep(&pr2);
-+ if( rc!=SQLITE_OK ) goto err;
- break;
- case 0:
- plwCopy(&plwriter, &pr1);
-- plrStep(&pr1);
-- plrStep(&pr2);
-+ rc = plrStep(&pr1);
-+ if( rc!=SQLITE_OK ) goto err;
-+ rc = plrStep(&pr2);
-+ if( rc!=SQLITE_OK ) goto err;
- break;
- }
- }
- plwTerminate(&plwriter);
- }
-- dataBufferDestroy(&one);
-- dataBufferDestroy(&two);
-+ dataBufferReset(&one);
-+ dataBufferReset(&two);
- }
-- dlrStep(&left);
-- dlrStep(&right);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) goto err;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) goto err;
- }
- }
-
-+err:
-+ dataBufferDestroy(&one);
-+ dataBufferDestroy(&two);
- dlrDestroy(&left);
- dlrDestroy(&right);
- dlwDestroy(&writer);
-+ return rc;
- }
-
- /* We have two DL_DOCIDS doclists: pLeft and pRight.
- ** Write the intersection of these two doclists into pOut as a
- ** DL_DOCIDS doclist.
- */
--static void docListAndMerge(
-+static int docListAndMerge(
- const char *pLeft, int nLeft,
- const char *pRight, int nRight,
- DataBuffer *pOut /* Write the combined doclist here */
- ){
- DLReader left, right;
- DLWriter writer;
-+ int rc;
-
-- if( nLeft==0 || nRight==0 ) return;
-+ if( nLeft==0 || nRight==0 ) return SQLITE_OK;
-
-- dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-- dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ if( rc!=SQLITE_OK ){
-+ dlrDestroy(&left);
-+ return rc;
-+ }
- dlwInit(&writer, DL_DOCIDS, pOut);
-
- while( !dlrAtEnd(&left) && !dlrAtEnd(&right) ){
- if( dlrDocid(&left)<dlrDocid(&right) ){
-- dlrStep(&left);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrDocid(&right)<dlrDocid(&left) ){
-- dlrStep(&right);
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
- dlwAdd(&writer, dlrDocid(&left));
-- dlrStep(&left);
-- dlrStep(&right);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
-
- dlrDestroy(&left);
- dlrDestroy(&right);
- dlwDestroy(&writer);
-+ return rc;
- }
-
- /* We have two DL_DOCIDS doclists: pLeft and pRight.
- ** Write the union of these two doclists into pOut as a
- ** DL_DOCIDS doclist.
- */
--static void docListOrMerge(
-+static int docListOrMerge(
- const char *pLeft, int nLeft,
- const char *pRight, int nRight,
- DataBuffer *pOut /* Write the combined doclist here */
- ){
- DLReader left, right;
- DLWriter writer;
-+ int rc;
-
- if( nLeft==0 ){
- if( nRight!=0 ) dataBufferAppend(pOut, pRight, nRight);
-- return;
-+ return SQLITE_OK;
- }
- if( nRight==0 ){
- dataBufferAppend(pOut, pLeft, nLeft);
-- return;
-+ return SQLITE_OK;
- }
-
-- dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-- dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ if( rc!=SQLITE_OK ){
-+ dlrDestroy(&left);
-+ return rc;
-+ }
- dlwInit(&writer, DL_DOCIDS, pOut);
-
- while( !dlrAtEnd(&left) || !dlrAtEnd(&right) ){
- if( dlrAtEnd(&right) ){
- dlwAdd(&writer, dlrDocid(&left));
-- dlrStep(&left);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrAtEnd(&left) ){
- dlwAdd(&writer, dlrDocid(&right));
-- dlrStep(&right);
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrDocid(&left)<dlrDocid(&right) ){
- dlwAdd(&writer, dlrDocid(&left));
-- dlrStep(&left);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }else if( dlrDocid(&right)<dlrDocid(&left) ){
- dlwAdd(&writer, dlrDocid(&right));
-- dlrStep(&right);
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }else{
- dlwAdd(&writer, dlrDocid(&left));
-- dlrStep(&left);
-- dlrStep(&right);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
-
- dlrDestroy(&left);
- dlrDestroy(&right);
- dlwDestroy(&writer);
-+ return rc;
- }
-
- /* We have two DL_DOCIDS doclists: pLeft and pRight.
- ** Write into pOut as DL_DOCIDS doclist containing all documents that
- ** occur in pLeft but not in pRight.
- */
--static void docListExceptMerge(
-+static int docListExceptMerge(
- const char *pLeft, int nLeft,
- const char *pRight, int nRight,
- DataBuffer *pOut /* Write the combined doclist here */
- ){
- DLReader left, right;
- DLWriter writer;
-+ int rc;
-
-- if( nLeft==0 ) return;
-+ if( nLeft==0 ) return SQLITE_OK;
- if( nRight==0 ){
- dataBufferAppend(pOut, pLeft, nLeft);
-- return;
-+ return SQLITE_OK;
- }
-
-- dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-- dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ rc = dlrInit(&left, DL_DOCIDS, pLeft, nLeft);
-+ if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrInit(&right, DL_DOCIDS, pRight, nRight);
-+ if( rc!=SQLITE_OK ){
-+ dlrDestroy(&left);
-+ return rc;
-+ }
- dlwInit(&writer, DL_DOCIDS, pOut);
-
- while( !dlrAtEnd(&left) ){
- while( !dlrAtEnd(&right) && dlrDocid(&right)<dlrDocid(&left) ){
-- dlrStep(&right);
-+ rc = dlrStep(&right);
-+ if( rc!=SQLITE_OK ) goto err;
- }
- if( dlrAtEnd(&right) || dlrDocid(&left)<dlrDocid(&right) ){
- dlwAdd(&writer, dlrDocid(&left));
- }
-- dlrStep(&left);
-+ rc = dlrStep(&left);
-+ if( rc!=SQLITE_OK ) break;
- }
-
-+err:
- dlrDestroy(&left);
- dlrDestroy(&right);
- dlwDestroy(&writer);
-+ return rc;
- }
-
- static char *string_dup_n(const char *s, int n){
-@@ -1858,7 +2036,7 @@
- /* SEGDIR_MAX_INDEX */ "select max(idx) from %_segdir where level = ?",
- /* SEGDIR_SET */ "insert into %_segdir values (?, ?, ?, ?, ?, ?)",
- /* SEGDIR_SELECT_LEVEL */
-- "select start_block, leaves_end_block, root from %_segdir "
-+ "select start_block, leaves_end_block, root, idx from %_segdir "
- " where level = ? order by idx",
- /* SEGDIR_SPAN */
- "select min(start_block), max(end_block) from %_segdir "
-@@ -3680,16 +3858,19 @@
- return SQLITE_OK;
- }
- rc = sqlite3_bind_int64(c->pStmt, 1, dlrDocid(&c->reader));
-- dlrStep(&c->reader);
- if( rc!=SQLITE_OK ) return rc;
-+ rc = dlrStep(&c->reader);
-+ if( rc!=SQLITE_OK ) return rc;
- /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */
- rc = sqlite3_step(c->pStmt);
- if( rc==SQLITE_ROW ){ /* the case we expect */
- c->eof = 0;
- return SQLITE_OK;
- }
-- /* an error occurred; abort */
-- return rc==SQLITE_DONE ? SQLITE_ERROR : rc;
-+ /* Corrupt if the index refers to missing document. */
-+ if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT;
-+
-+ return rc;
- }
- }
-
-@@ -3739,11 +3920,12 @@
- if( ii==(pPhrase->nToken-1) ){
- eType = eListType;
- }
-- docListPhraseMerge(
-+ rc = docListPhraseMerge(
- res.pData, res.nData, tmp.pData, tmp.nData, 0, 0, eType, pResult
- );
- dataBufferDestroy(&res);
- dataBufferDestroy(&tmp);
-+ if( rc!= SQLITE_OK ) return rc;
- }
- }
- }
-@@ -3798,21 +3980,21 @@
- assert( pExpr->pRight->eType==FTSQUERY_PHRASE );
- assert( pLeft->eType==FTSQUERY_PHRASE );
- nToken = pLeft->pPhrase->nToken + pExpr->pRight->pPhrase->nToken;
-- docListPhraseMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,
-+ rc = docListPhraseMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,
- pExpr->nNear+1, nToken, eType, pRes
- );
- break;
- }
- case FTSQUERY_NOT: {
-- docListExceptMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,pRes);
-+ rc = docListExceptMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData,pRes);
- break;
- }
- case FTSQUERY_AND: {
-- docListAndMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes);
-+ rc = docListAndMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes);
- break;
- }
- case FTSQUERY_OR: {
-- docListOrMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes);
-+ rc = docListOrMerge(lhs.pData, lhs.nData, rhs.pData, rhs.nData, pRes);
- break;
- }
- }
-@@ -4469,22 +4651,19 @@
- SCRAMBLE(pReader);
- }
-
--/* TODO(shess) The assertions are great, but what if we're in NDEBUG
--** and the blob is empty or otherwise contains suspect data?
--*/
--static void interiorReaderInit(const char *pData, int nData,
-- InteriorReader *pReader){
-+static int interiorReaderInit(const char *pData, int nData,
-+ InteriorReader *pReader){
- int n, nTerm;
-
-- /* Require at least the leading flag byte */
-+ /* These conditions are checked and met by the callers. */
- assert( nData>0 );
- assert( pData[0]!='\0' );
-
- CLEAR(pReader);
-
- /* Decode the base blockid, and set the cursor to the first term. */
-- n = fts3GetVarint(pData+1, &pReader->iBlockid);
-- assert( 1+n<=nData );
-+ n = fts3GetVarintSafe(pData+1, &pReader->iBlockid, nData-1);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
- pReader->pData = pData+1+n;
- pReader->nData = nData-(1+n);
-
-@@ -4495,17 +4674,18 @@
- if( pReader->nData==0 ){
- dataBufferInit(&pReader->term, 0);
- }else{
-- n = fts3GetVarint32(pReader->pData, &nTerm);
-+ n = fts3GetVarint32Safe(pReader->pData, &nTerm, pReader->nData);
-+ if( !n || nTerm<0 || nTerm>pReader->nData-n) return SQLITE_CORRUPT_BKPT;
- dataBufferInit(&pReader->term, nTerm);
- dataBufferReplace(&pReader->term, pReader->pData+n, nTerm);
-- assert( n+nTerm<=pReader->nData );
- pReader->pData += n+nTerm;
- pReader->nData -= n+nTerm;
- }
-+ return SQLITE_OK;
- }
-
- static int interiorReaderAtEnd(InteriorReader *pReader){
-- return pReader->term.nData==0;
-+ return pReader->term.nData<=0;
- }
-
- static sqlite_int64 interiorReaderCurrentBlockid(InteriorReader *pReader){
-@@ -4522,7 +4702,7 @@
- }
-
- /* Step forward to the next term in the node. */
--static void interiorReaderStep(InteriorReader *pReader){
-+static int interiorReaderStep(InteriorReader *pReader){
- assert( !interiorReaderAtEnd(pReader) );
-
- /* If the last term has been read, signal eof, else construct the
-@@ -4533,18 +4713,26 @@
- }else{
- int n, nPrefix, nSuffix;
-
-- n = fts3GetVarint32(pReader->pData, &nPrefix);
-- n += fts3GetVarint32(pReader->pData+n, &nSuffix);
-+ n = fts3GetVarint32Safe(pReader->pData, &nPrefix, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ pReader->nData -= n;
-+ pReader->pData += n;
-+ n = fts3GetVarint32Safe(pReader->pData, &nSuffix, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ pReader->nData -= n;
-+ pReader->pData += n;
-+ if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT;
-+ if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT;
-
- /* Truncate the current term and append suffix data. */
- pReader->term.nData = nPrefix;
-- dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix);
-+ dataBufferAppend(&pReader->term, pReader->pData, nSuffix);
-
-- assert( n+nSuffix<=pReader->nData );
-- pReader->pData += n+nSuffix;
-- pReader->nData -= n+nSuffix;
-+ pReader->pData += nSuffix;
-+ pReader->nData -= nSuffix;
- }
- pReader->iBlockid++;
-+ return SQLITE_OK;
- }
-
- /* Compare the current term to pTerm[nTerm], returning strcmp-style
-@@ -4916,7 +5104,8 @@
- n = fts3PutVarint(c, nData);
- dataBufferAppend(&pWriter->data, c, n);
-
-- docListMerge(&pWriter->data, pReaders, nReaders);
-+ rc = docListMerge(&pWriter->data, pReaders, nReaders);
-+ if( rc!=SQLITE_OK ) return rc;
- ASSERT_VALID_DOCLIST(DL_DEFAULT,
- pWriter->data.pData+iDoclistData+n,
- pWriter->data.nData-iDoclistData-n, NULL);
-@@ -5026,7 +5215,8 @@
- int rc;
- DLReader reader;
-
-- dlrInit(&reader, DL_DEFAULT, pData, nData);
-+ rc = dlrInit(&reader, DL_DEFAULT, pData, nData);
-+ if( rc!=SQLITE_OK ) return rc;
- rc = leafWriterStepMerge(v, pWriter, pTerm, nTerm, &reader, 1);
- dlrDestroy(&reader);
-
-@@ -5071,38 +5261,41 @@
- static const char *leafReaderData(LeafReader *pReader){
- int n, nData;
- assert( pReader->term.nData>0 );
-- n = fts3GetVarint32(pReader->pData, &nData);
-+ n = fts3GetVarint32Safe(pReader->pData, &nData, pReader->nData);
-+ if( !n || nData>pReader->nData-n ) return NULL;
- return pReader->pData+n;
- }
-
--static void leafReaderInit(const char *pData, int nData,
-- LeafReader *pReader){
-+static int leafReaderInit(const char *pData, int nData,
-+ LeafReader *pReader){
- int nTerm, n;
-
-+ /* All callers check this precondition. */
- assert( nData>0 );
- assert( pData[0]=='\0' );
-
- CLEAR(pReader);
-
- /* Read the first term, skipping the header byte. */
-- n = fts3GetVarint32(pData+1, &nTerm);
-+ n = fts3GetVarint32Safe(pData+1, &nTerm, nData-1);
-+ if( !n || nTerm<0 || nTerm>nData-1-n ) return SQLITE_CORRUPT_BKPT;
- dataBufferInit(&pReader->term, nTerm);
- dataBufferReplace(&pReader->term, pData+1+n, nTerm);
-
- /* Position after the first term. */
-- assert( 1+n+nTerm<nData );
- pReader->pData = pData+1+n+nTerm;
- pReader->nData = nData-1-n-nTerm;
-+ return SQLITE_OK;
- }
-
- /* Step the reader forward to the next term. */
--static void leafReaderStep(LeafReader *pReader){
-+static int leafReaderStep(LeafReader *pReader){
- int n, nData, nPrefix, nSuffix;
- assert( !leafReaderAtEnd(pReader) );
-
- /* Skip previous entry's data block. */
-- n = fts3GetVarint32(pReader->pData, &nData);
-- assert( n+nData<=pReader->nData );
-+ n = fts3GetVarint32Safe(pReader->pData, &nData, pReader->nData);
-+ if( !n || nData<0 || nData>pReader->nData-n ) return SQLITE_CORRUPT_BKPT;
- pReader->pData += n+nData;
- pReader->nData -= n+nData;
-
-@@ -5110,15 +5303,23 @@
- /* Construct the new term using a prefix from the old term plus a
- ** suffix from the leaf data.
- */
-- n = fts3GetVarint32(pReader->pData, &nPrefix);
-- n += fts3GetVarint32(pReader->pData+n, &nSuffix);
-- assert( n+nSuffix<pReader->nData );
-+ n = fts3GetVarint32Safe(pReader->pData, &nPrefix, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ pReader->nData -= n;
-+ pReader->pData += n;
-+ n = fts3GetVarint32Safe(pReader->pData, &nSuffix, pReader->nData);
-+ if( !n ) return SQLITE_CORRUPT_BKPT;
-+ pReader->nData -= n;
-+ pReader->pData += n;
-+ if( nSuffix<0 || nSuffix>pReader->nData ) return SQLITE_CORRUPT_BKPT;
-+ if( nPrefix<0 || nPrefix>pReader->term.nData ) return SQLITE_CORRUPT_BKPT;
- pReader->term.nData = nPrefix;
-- dataBufferAppend(&pReader->term, pReader->pData+n, nSuffix);
-+ dataBufferAppend(&pReader->term, pReader->pData, nSuffix);
-
-- pReader->pData += n+nSuffix;
-- pReader->nData -= n+nSuffix;
-+ pReader->pData += nSuffix;
-+ pReader->nData -= nSuffix;
- }
-+ return SQLITE_OK;
- }
-
- /* strcmp-style comparison of pReader's current term against pTerm.
-@@ -5222,32 +5423,67 @@
-
- dataBufferInit(&pReader->rootData, 0);
- if( iStartBlockid==0 ){
-+ int rc;
-+ /* Corrupt if this can't be a leaf node. */
-+ if( pRootData==NULL || nRootData<1 || pRootData[0]!='\0' ){
-+ return SQLITE_CORRUPT_BKPT;
-+ }
- /* Entire leaf level fit in root data. */
- dataBufferReplace(&pReader->rootData, pRootData, nRootData);
-- leafReaderInit(pReader->rootData.pData, pReader->rootData.nData,
-- &pReader->leafReader);
-+ rc = leafReaderInit(pReader->rootData.pData, pReader->rootData.nData,
-+ &pReader->leafReader);
-+ if( rc!=SQLITE_OK ){
-+ dataBufferDestroy(&pReader->rootData);
-+ return rc;
-+ }
- }else{
- sqlite3_stmt *s;
- int rc = sql_get_leaf_statement(v, idx, &s);
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3_bind_int64(s, 1, iStartBlockid);
-- if( rc!=SQLITE_OK ) return rc;
-+ if( rc!=SQLITE_OK ) goto err;
-
- rc = sqlite3_bind_int64(s, 2, iEndBlockid);
-- if( rc!=SQLITE_OK ) return rc;
-+ if( rc!=SQLITE_OK ) goto err;
-
- rc = sqlite3_step(s);
-+
-+ /* Corrupt if interior node referenced missing leaf node. */
- if( rc==SQLITE_DONE ){
-- pReader->eof = 1;
-- return SQLITE_OK;
-+ rc = SQLITE_CORRUPT_BKPT;
-+ goto err;
- }
-- if( rc!=SQLITE_ROW ) return rc;
-
-+ if( rc!=SQLITE_ROW ) goto err;
-+ rc = SQLITE_OK;
-+
-+ /* Corrupt if leaf data isn't a blob. */
-+ if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ }else{
-+ const char *pLeafData = sqlite3_column_blob(s, 0);
-+ int nLeafData = sqlite3_column_bytes(s, 0);
-+
-+ /* Corrupt if this can't be a leaf node. */
-+ if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ }else{
-+ rc = leafReaderInit(pLeafData, nLeafData, &pReader->leafReader);
-+ }
-+ }
-+
-+ err:
-+ if( rc!=SQLITE_OK ){
-+ if( idx==-1 ){
-+ sqlite3_finalize(s);
-+ }else{
-+ sqlite3_reset(s);
-+ }
-+ return rc;
-+ }
-+
- pReader->pStmt = s;
-- leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0),
-- sqlite3_column_bytes(pReader->pStmt, 0),
-- &pReader->leafReader);
- }
- return SQLITE_OK;
- }
-@@ -5256,11 +5492,12 @@
- ** end of the current leaf, step forward to the next leaf block.
- */
- static int leavesReaderStep(fulltext_vtab *v, LeavesReader *pReader){
-+ int rc;
- assert( !leavesReaderAtEnd(pReader) );
-- leafReaderStep(&pReader->leafReader);
-+ rc = leafReaderStep(&pReader->leafReader);
-+ if( rc!=SQLITE_OK ) return rc;
-
- if( leafReaderAtEnd(&pReader->leafReader) ){
-- int rc;
- if( pReader->rootData.pData ){
- pReader->eof = 1;
- return SQLITE_OK;
-@@ -5270,10 +5507,25 @@
- pReader->eof = 1;
- return rc==SQLITE_DONE ? SQLITE_OK : rc;
- }
-- leafReaderDestroy(&pReader->leafReader);
-- leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0),
-- sqlite3_column_bytes(pReader->pStmt, 0),
-- &pReader->leafReader);
-+
-+ /* Corrupt if leaf data isn't a blob. */
-+ if( sqlite3_column_type(pReader->pStmt, 0)!=SQLITE_BLOB ){
-+ return SQLITE_CORRUPT_BKPT;
-+ }else{
-+ LeafReader tmp;
-+ const char *pLeafData = sqlite3_column_blob(pReader->pStmt, 0);
-+ int nLeafData = sqlite3_column_bytes(pReader->pStmt, 0);
-+
-+ /* Corrupt if this can't be a leaf node. */
-+ if( pLeafData==NULL || nLeafData<1 || pLeafData[0]!='\0' ){
-+ return SQLITE_CORRUPT_BKPT;
-+ }
-+
-+ rc = leafReaderInit(pLeafData, nLeafData, &tmp);
-+ if( rc!=SQLITE_OK ) return rc;
-+ leafReaderDestroy(&pReader->leafReader);
-+ pReader->leafReader = tmp;
-+ }
- }
- return SQLITE_OK;
- }
-@@ -5334,8 +5586,19 @@
- sqlite_int64 iEnd = sqlite3_column_int64(s, 1);
- const char *pRootData = sqlite3_column_blob(s, 2);
- int nRootData = sqlite3_column_bytes(s, 2);
-+ sqlite_int64 iIndex = sqlite3_column_int64(s, 3);
-
-- assert( i<MERGE_COUNT );
-+ /* Corrupt if we get back different types than we stored. */
-+ /* Also corrupt if the index is not sequential starting at 0. */
-+ if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 1)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 2)!=SQLITE_BLOB ||
-+ i!=iIndex ||
-+ i>=MERGE_COUNT ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+
- rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData,
- &pReaders[i]);
- if( rc!=SQLITE_OK ) break;
-@@ -5346,6 +5609,7 @@
- while( i-->0 ){
- leavesReaderDestroy(&pReaders[i]);
- }
-+ sqlite3_reset(s); /* So we don't leave a lock. */
- return rc;
- }
-
-@@ -5369,14 +5633,27 @@
- DLReader dlReaders[MERGE_COUNT];
- const char *pTerm = leavesReaderTerm(pReaders);
- int i, nTerm = leavesReaderTermBytes(pReaders);
-+ int rc;
-
- assert( nReaders<=MERGE_COUNT );
-
- for(i=0; i<nReaders; i++){
-- dlrInit(&dlReaders[i], DL_DEFAULT,
-- leavesReaderData(pReaders+i),
-- leavesReaderDataBytes(pReaders+i));
-+ const char *pData = leavesReaderData(pReaders+i);
-+ if( pData==NULL ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+ rc = dlrInit(&dlReaders[i], DL_DEFAULT,
-+ pData,
-+ leavesReaderDataBytes(pReaders+i));
-+ if( rc!=SQLITE_OK ) break;
- }
-+ if( rc!=SQLITE_OK ){
-+ while( i-->0 ){
-+ dlrDestroy(&dlReaders[i]);
-+ }
-+ return rc;
-+ }
-
- return leafWriterStepMerge(v, pWriter, pTerm, nTerm, dlReaders, nReaders);
- }
-@@ -5429,10 +5706,14 @@
- memset(&lrs, '\0', sizeof(lrs));
- rc = leavesReadersInit(v, iLevel, lrs, &i);
- if( rc!=SQLITE_OK ) return rc;
-- assert( i==MERGE_COUNT );
-
- leafWriterInit(iLevel+1, idx, &writer);
-
-+ if( i!=MERGE_COUNT ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ goto err;
-+ }
-+
- /* Since leavesReaderReorder() pushes readers at eof to the end,
- ** when the first reader is empty, all will be empty.
- */
-@@ -5475,12 +5756,14 @@
- }
-
- /* Accumulate the union of *acc and *pData into *acc. */
--static void docListAccumulateUnion(DataBuffer *acc,
-- const char *pData, int nData) {
-+static int docListAccumulateUnion(DataBuffer *acc,
-+ const char *pData, int nData) {
- DataBuffer tmp = *acc;
-+ int rc;
- dataBufferInit(acc, tmp.nData+nData);
-- docListUnion(tmp.pData, tmp.nData, pData, nData, acc);
-+ rc = docListUnion(tmp.pData, tmp.nData, pData, nData, acc);
- dataBufferDestroy(&tmp);
-+ return rc;
- }
-
- /* TODO(shess) It might be interesting to explore different merge
-@@ -5522,8 +5805,13 @@
- int c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm, isPrefix);
- if( c>0 ) break; /* Past any possible matches. */
- if( c==0 ){
-+ int iBuffer, nData;
- const char *pData = leavesReaderData(pReader);
-- int iBuffer, nData = leavesReaderDataBytes(pReader);
-+ if( pData==NULL ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+ nData = leavesReaderDataBytes(pReader);
-
- /* Find the first empty buffer. */
- for(iBuffer=0; iBuffer<nBuffers; ++iBuffer){
-@@ -5569,11 +5857,13 @@
- ** with pData/nData.
- */
- dataBufferSwap(p, pAcc);
-- docListAccumulateUnion(pAcc, pData, nData);
-+ rc = docListAccumulateUnion(pAcc, pData, nData);
-+ if( rc!=SQLITE_OK ) goto err;
-
- /* Accumulate remaining doclists into pAcc. */
- for(++p; p<pAcc; ++p){
-- docListAccumulateUnion(pAcc, p->pData, p->nData);
-+ rc = docListAccumulateUnion(pAcc, p->pData, p->nData);
-+ if( rc!=SQLITE_OK ) goto err;
-
- /* dataBufferReset() could allow a large doclist to blow up
- ** our memory requirements.
-@@ -5598,13 +5888,15 @@
- if( out->nData==0 ){
- dataBufferSwap(out, &(pBuffers[iBuffer]));
- }else{
-- docListAccumulateUnion(out, pBuffers[iBuffer].pData,
-- pBuffers[iBuffer].nData);
-+ rc = docListAccumulateUnion(out, pBuffers[iBuffer].pData,
-+ pBuffers[iBuffer].nData);
-+ if( rc!=SQLITE_OK ) break;
- }
- }
- }
- }
-
-+err:
- while( nBuffers-- ){
- dataBufferDestroy(&(pBuffers[nBuffers]));
- }
-@@ -5663,20 +5955,26 @@
- ** node. Consider whether breaking symmetry is worthwhile. I suspect
- ** it is not worthwhile.
- */
--static void getChildrenContaining(const char *pData, int nData,
-- const char *pTerm, int nTerm, int isPrefix,
-- sqlite_int64 *piStartChild,
-- sqlite_int64 *piEndChild){
-+static int getChildrenContaining(const char *pData, int nData,
-+ const char *pTerm, int nTerm, int isPrefix,
-+ sqlite_int64 *piStartChild,
-+ sqlite_int64 *piEndChild){
- InteriorReader reader;
-+ int rc;
-
- assert( nData>1 );
- assert( *pData!='\0' );
-- interiorReaderInit(pData, nData, &reader);
-+ rc = interiorReaderInit(pData, nData, &reader);
-+ if( rc!=SQLITE_OK ) return rc;
-
- /* Scan for the first child which could contain pTerm/nTerm. */
- while( !interiorReaderAtEnd(&reader) ){
- if( interiorReaderTermCmp(&reader, pTerm, nTerm, 0)>0 ) break;
-- interiorReaderStep(&reader);
-+ rc = interiorReaderStep(&reader);
-+ if( rc!=SQLITE_OK ){
-+ interiorReaderDestroy(&reader);
-+ return rc;
-+ }
- }
- *piStartChild = interiorReaderCurrentBlockid(&reader);
-
-@@ -5686,7 +5984,11 @@
- */
- while( !interiorReaderAtEnd(&reader) ){
- if( interiorReaderTermCmp(&reader, pTerm, nTerm, isPrefix)>0 ) break;
-- interiorReaderStep(&reader);
-+ rc = interiorReaderStep(&reader);
-+ if( rc!=SQLITE_OK ){
-+ interiorReaderDestroy(&reader);
-+ return rc;
-+ }
- }
- *piEndChild = interiorReaderCurrentBlockid(&reader);
-
-@@ -5695,6 +5997,7 @@
- /* Children must ascend, and if !prefix, both must be the same. */
- assert( *piEndChild>=*piStartChild );
- assert( isPrefix || *piStartChild==*piEndChild );
-+ return rc;
- }
-
- /* Read block at iBlockid and pass it with other params to
-@@ -5722,12 +6025,32 @@
- if( rc!=SQLITE_OK ) return rc;
-
- rc = sqlite3_step(s);
-- if( rc==SQLITE_DONE ) return SQLITE_ERROR;
-+ /* Corrupt if interior node references missing child node. */
-+ if( rc==SQLITE_DONE ) return SQLITE_CORRUPT_BKPT;
- if( rc!=SQLITE_ROW ) return rc;
-
-- getChildrenContaining(sqlite3_column_blob(s, 0), sqlite3_column_bytes(s, 0),
-- pTerm, nTerm, isPrefix, piStartChild, piEndChild);
-+ /* Corrupt if child node isn't a blob. */
-+ if( sqlite3_column_type(s, 0)!=SQLITE_BLOB ){
-+ sqlite3_reset(s); /* So we don't leave a lock. */
-+ return SQLITE_CORRUPT_BKPT;
-+ }else{
-+ const char *pData = sqlite3_column_blob(s, 0);
-+ int nData = sqlite3_column_bytes(s, 0);
-
-+ /* Corrupt if child is not a valid interior node. */
-+ if( pData==NULL || nData<1 || pData[0]=='\0' ){
-+ sqlite3_reset(s); /* So we don't leave a lock. */
-+ return SQLITE_CORRUPT_BKPT;
-+ }
-+
-+ rc = getChildrenContaining(pData, nData, pTerm, nTerm,
-+ isPrefix, piStartChild, piEndChild);
-+ if( rc!=SQLITE_OK ){
-+ sqlite3_reset(s);
-+ return rc;
-+ }
-+ }
-+
- /* We expect only one row. We must execute another sqlite3_step()
- * to complete the iteration; otherwise the table will remain
- * locked. */
-@@ -5756,8 +6079,9 @@
- /* Process pData as an interior node, then loop down the tree
- ** until we find the set of leaf nodes to scan for the term.
- */
-- getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix,
-- &iStartChild, &iEndChild);
-+ rc = getChildrenContaining(pData, nData, pTerm, nTerm, isPrefix,
-+ &iStartChild, &iEndChild);
-+ if( rc!=SQLITE_OK ) return rc;
- while( iStartChild>iLeavesEnd ){
- sqlite_int64 iNextStart, iNextEnd;
- rc = loadAndGetChildrenContaining(v, iStartChild, pTerm, nTerm, isPrefix,
-@@ -5809,7 +6133,8 @@
- DataBuffer result;
- int rc;
-
-- assert( nData>1 );
-+ /* Corrupt if segment root can't be valid. */
-+ if( pData==NULL || nData<1 ) return SQLITE_CORRUPT_BKPT;
-
- /* This code should never be called with buffered updates. */
- assert( v->nPendingData<0 );
-@@ -5826,16 +6151,21 @@
- DataBuffer merged;
- DLReader readers[2];
-
-- dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData);
-- dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData);
-- dataBufferInit(&merged, out->nData+result.nData);
-- docListMerge(&merged, readers, 2);
-- dataBufferDestroy(out);
-- *out = merged;
-- dlrDestroy(&readers[0]);
-- dlrDestroy(&readers[1]);
-+ rc = dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData);
-+ if( rc==SQLITE_OK ){
-+ rc = dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData);
-+ if( rc==SQLITE_OK ){
-+ dataBufferInit(&merged, out->nData+result.nData);
-+ rc = docListMerge(&merged, readers, 2);
-+ dataBufferDestroy(out);
-+ *out = merged;
-+ dlrDestroy(&readers[1]);
-+ }
-+ dlrDestroy(&readers[0]);
-+ }
- }
- }
-+
- dataBufferDestroy(&result);
- return rc;
- }
-@@ -5869,11 +6199,20 @@
- const char *pData = sqlite3_column_blob(s, 2);
- const int nData = sqlite3_column_bytes(s, 2);
- const sqlite_int64 iLeavesEnd = sqlite3_column_int64(s, 1);
-+
-+ /* Corrupt if we get back different types than we stored. */
-+ if( sqlite3_column_type(s, 1)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 2)!=SQLITE_BLOB ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ goto err;
-+ }
-+
- rc = loadSegment(v, pData, nData, iLeavesEnd, pTerm, nTerm, isPrefix,
- &doclist);
- if( rc!=SQLITE_OK ) goto err;
- }
- if( rc==SQLITE_DONE ){
-+ rc = SQLITE_OK;
- if( doclist.nData!=0 ){
- /* TODO(shess) The old term_select_all() code applied the column
- ** restrict as we merged segments, leading to smaller buffers.
-@@ -5881,13 +6220,13 @@
- ** system is checked in.
- */
- if( iColumn==v->nColumn) iColumn = -1;
-- docListTrim(DL_DEFAULT, doclist.pData, doclist.nData,
-- iColumn, iType, out);
-+ rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData,
-+ iColumn, iType, out);
- }
-- rc = SQLITE_OK;
- }
-
- err:
-+ sqlite3_reset(s); /* So we don't leave a lock. */
- dataBufferDestroy(&doclist);
- return rc;
- }
-@@ -6250,6 +6589,7 @@
- LeafWriter *pWriter){
- int i, rc = SQLITE_OK;
- DataBuffer doclist, merged, tmp;
-+ const char *pData;
-
- /* Order the readers. */
- i = nReaders;
-@@ -6270,14 +6610,20 @@
- if( 0!=optLeavesReaderTermCmp(&readers[0], &readers[i]) ) break;
- }
-
-+ pData = optLeavesReaderData(&readers[0]);
-+ if( pData==NULL ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+
- /* Special-case for no merge. */
- if( i==1 ){
- /* Trim deletions from the doclist. */
- dataBufferReset(&merged);
-- docListTrim(DL_DEFAULT,
-- optLeavesReaderData(&readers[0]),
-- optLeavesReaderDataBytes(&readers[0]),
-- -1, DL_DEFAULT, &merged);
-+ rc = docListTrim(DL_DEFAULT, pData,
-+ optLeavesReaderDataBytes(&readers[0]),
-+ -1, DL_DEFAULT, &merged);
-+ if( rc!=SQLITE_OK ) break;
- }else{
- DLReader dlReaders[MERGE_COUNT];
- int iReader, nReaders;
-@@ -6285,9 +6631,10 @@
- /* Prime the pipeline with the first reader's doclist. After
- ** one pass index 0 will reference the accumulated doclist.
- */
-- dlrInit(&dlReaders[0], DL_DEFAULT,
-- optLeavesReaderData(&readers[0]),
-- optLeavesReaderDataBytes(&readers[0]));
-+ rc = dlrInit(&dlReaders[0], DL_DEFAULT,
-+ pData,
-+ optLeavesReaderDataBytes(&readers[0]));
-+ if( rc!=SQLITE_OK ) break;
- iReader = 1;
-
- assert( iReader<i ); /* Must execute the loop at least once. */
-@@ -6295,24 +6642,34 @@
- /* Merge 16 inputs per pass. */
- for( nReaders=1; iReader<i && nReaders<MERGE_COUNT;
- iReader++, nReaders++ ){
-- dlrInit(&dlReaders[nReaders], DL_DEFAULT,
-- optLeavesReaderData(&readers[iReader]),
-- optLeavesReaderDataBytes(&readers[iReader]));
-+ pData = optLeavesReaderData(&readers[iReader]);
-+ if( pData==NULL ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+ rc = dlrInit(&dlReaders[nReaders], DL_DEFAULT, pData,
-+ optLeavesReaderDataBytes(&readers[iReader]));
-+ if( rc!=SQLITE_OK ) break;
- }
-
- /* Merge doclists and swap result into accumulator. */
-- dataBufferReset(&merged);
-- docListMerge(&merged, dlReaders, nReaders);
-- tmp = merged;
-- merged = doclist;
-- doclist = tmp;
-+ if( rc==SQLITE_OK ){
-+ dataBufferReset(&merged);
-+ rc = docListMerge(&merged, dlReaders, nReaders);
-+ tmp = merged;
-+ merged = doclist;
-+ doclist = tmp;
-+ }
-
- while( nReaders-- > 0 ){
- dlrDestroy(&dlReaders[nReaders]);
- }
-
-+ if( rc!=SQLITE_OK ) goto err;
-+
- /* Accumulated doclist to reader 0 for next pass. */
-- dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData);
-+ rc = dlrInit(&dlReaders[0], DL_DEFAULT, doclist.pData, doclist.nData);
-+ if( rc!=SQLITE_OK ) goto err;
- }
-
- /* Destroy reader that was left in the pipeline. */
-@@ -6320,8 +6677,9 @@
-
- /* Trim deletions from the doclist. */
- dataBufferReset(&merged);
-- docListTrim(DL_DEFAULT, doclist.pData, doclist.nData,
-- -1, DL_DEFAULT, &merged);
-+ rc = docListTrim(DL_DEFAULT, doclist.pData, doclist.nData,
-+ -1, DL_DEFAULT, &merged);
-+ if( rc!=SQLITE_OK ) goto err;
- }
-
- /* Only pass doclists with hits (skip if all hits deleted). */
-@@ -6401,6 +6759,14 @@
- const char *pRootData = sqlite3_column_blob(s, 2);
- int nRootData = sqlite3_column_bytes(s, 2);
-
-+ /* Corrupt if we get back different types than we stored. */
-+ if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 1)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 2)!=SQLITE_BLOB ){
-+ rc = SQLITE_CORRUPT_BKPT;
-+ break;
-+ }
-+
- assert( i<nReaders );
- rc = leavesReaderInit(v, -1, iStart, iEnd, pRootData, nRootData,
- &readers[i].reader);
-@@ -6414,6 +6780,8 @@
- if( rc==SQLITE_DONE ){
- assert( i==nReaders );
- rc = optimizeInternal(v, readers, nReaders, &writer);
-+ }else{
-+ sqlite3_reset(s); /* So we don't leave a lock. */
- }
-
- while( i-- > 0 ){
-@@ -6477,9 +6845,18 @@
- const sqlite_int64 iEndBlockid = sqlite3_column_int64(s, 1);
- const char *pRootData = sqlite3_column_blob(s, 2);
- const int nRootData = sqlite3_column_bytes(s, 2);
-+ int rc;
- LeavesReader reader;
-- int rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid,
-- pRootData, nRootData, &reader);
-+
-+ /* Corrupt if we get back different types than we stored. */
-+ if( sqlite3_column_type(s, 0)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 1)!=SQLITE_INTEGER ||
-+ sqlite3_column_type(s, 2)!=SQLITE_BLOB ){
-+ return SQLITE_CORRUPT_BKPT;
-+ }
-+
-+ rc = leavesReaderInit(v, 0, iStartBlockid, iEndBlockid,
-+ pRootData, nRootData, &reader);
- if( rc!=SQLITE_OK ) return rc;
-
- while( rc==SQLITE_OK && !leavesReaderAtEnd(&reader) ){
-@@ -6641,16 +7018,19 @@
- const char *pData, int nData){
- DataBuffer dump;
- DLReader dlReader;
-+ int rc;
-
- assert( pData!=NULL && nData>0 );
-
-+ rc = dlrInit(&dlReader, DL_DEFAULT, pData, nData);
-+ if( rc!=SQLITE_OK ) return rc;
- dataBufferInit(&dump, 0);
-- dlrInit(&dlReader, DL_DEFAULT, pData, nData);
-- for( ; !dlrAtEnd(&dlReader); dlrStep(&dlReader) ){
-+ for( ; rc==SQLITE_OK && !dlrAtEnd(&dlReader); rc = dlrStep(&dlReader) ){
- char buf[256];
- PLReader plReader;
-
-- plrInit(&plReader, &dlReader);
-+ rc = plrInit(&plReader, &dlReader);
-+ if( rc!=SQLITE_OK ) break;
- if( DL_DEFAULT==DL_DOCIDS || plrAtEnd(&plReader) ){
- sqlite3_snprintf(sizeof(buf), buf, "[%lld] ", dlrDocid(&dlReader));
- dataBufferAppend(&dump, buf, strlen(buf));
-@@ -6661,7 +7041,8 @@
- dlrDocid(&dlReader), iColumn);
- dataBufferAppend(&dump, buf, strlen(buf));
-
-- for( ; !plrAtEnd(&plReader); plrStep(&plReader) ){
-+ for( ; !plrAtEnd(&plReader); rc = plrStep(&plReader) ){
-+ if( rc!=SQLITE_OK ) break;
- if( plrColumn(&plReader)!=iColumn ){
- iColumn = plrColumn(&plReader);
- sqlite3_snprintf(sizeof(buf), buf, "] %d[", iColumn);
-@@ -6682,6 +7063,7 @@
- dataBufferAppend(&dump, buf, strlen(buf));
- }
- plrDestroy(&plReader);
-+ if( rc!= SQLITE_OK ) break;
-
- assert( dump.nData>0 );
- dump.nData--; /* Overwrite trailing space. */
-@@ -6690,6 +7072,10 @@
- }
- }
- dlrDestroy(&dlReader);
-+ if( rc!=SQLITE_OK ){
-+ dataBufferDestroy(&dump);
-+ return rc;
-+ }
-
- assert( dump.nData>0 );
- dump.nData--; /* Overwrite trailing space. */
-@@ -6701,6 +7087,7 @@
- sqlite3_result_text(pContext, dump.pData, dump.nData, sqlite3_free);
- dump.pData = NULL;
- dump.nData = dump.nCapacity = 0;
-+ return SQLITE_OK;
- }
-
- /* Implements dump_doclist() for use in inspecting the fts3 index from
-@@ -6987,7 +7374,11 @@
+@@ -1226,7 +1227,13 @@ static int fts3ScanInteriorNode(
+ isFirstTerm = 0;
+ zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
+
+- if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
++ /* NOTE(shess): Previous code checked for negative nPrefix and
++ ** nSuffix and suffix overrunning zEnd. Additionally corrupt if
++ ** the prefix is longer than the previous term, or if the suffix
++ ** causes overflow.
++ */
++ if( nPrefix<0 || nSuffix<0 || nPrefix>nBuffer
++ || &zCsr[nSuffix]<zCsr || &zCsr[nSuffix]>zEnd ){
+ rc = SQLITE_CORRUPT;
+ goto finish_scan;
+ }
+@@ -3646,7 +3660,11 @@ int sqlite3Fts3Init(sqlite3 *db){
** module with sqlite.
*/
if( SQLITE_OK==rc
@@ -1897,13 +35,29 @@ Index: ext/fts3/fts3.c
&& SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
+#endif
&& SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
- && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", -1))
- && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", -1))
-Index: ext/fts3/fts3_icu.c
-===================================================================
---- ext/fts3/fts3_icu.c (revision 48811)
-+++ ext/fts3/fts3_icu.c (working copy)
-@@ -198,7 +198,7 @@
+ && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
+ && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
+@@ -3656,11 +3674,15 @@ int sqlite3Fts3Init(sqlite3 *db){
+ rc = sqlite3_create_module_v2(
+ db, "fts3", &fts3Module, (void *)pHash, hashDestroy
+ );
++#if CHROMIUM_FTS3_CHANGES && !SQLITE_TEST
++ /* Disable fts4 pending review. */
++#else
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_module_v2(
+ db, "fts4", &fts3Module, (void *)pHash, 0
+ );
+ }
++#endif
+ return rc;
+ }
+
+diff --git ext/fts3/fts3_icu.c ext/fts3/fts3_icu.c
+index 85390d3..a75b14a 100644
+--- ext/fts3/fts3_icu.c
++++ ext/fts3/fts3_icu.c
+@@ -198,7 +198,7 @@ static int icuNext(
while( iStart<iEnd ){
int iWhite = iStart;
@@ -1912,15 +66,3 @@ Index: ext/fts3/fts3_icu.c
if( u_isspace(c) ){
iStart = iWhite;
}else{
-Index: ext/fts3/fts3_tokenizer.c
-===================================================================
---- ext/fts3/fts3_tokenizer.c (revision 48811)
-+++ ext/fts3/fts3_tokenizer.c (working copy)
-@@ -33,6 +33,7 @@
- #include "fts3_hash.h"
- #include "fts3_tokenizer.h"
- #include <assert.h>
-+#include <stddef.h>
-
- /*
- ** Implementation of the SQL scalar function for accessing the underlying
« no previous file with comments | « third_party/sqlite/attach-integer.patch ('k') | third_party/sqlite/icu-regexp.patch » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698