Index: third_party/sqlite/misc.patch |
=================================================================== |
--- third_party/sqlite/misc.patch (revision 27190) |
+++ third_party/sqlite/misc.patch (working copy) |
@@ -95,396 +95,6 @@ |
} |
/* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. |
-Index: ext/fts2/fts2.c |
-=================================================================== |
---- ext/fts2/fts2.c 2009-09-04 13:37:41.000000000 -0700 |
-+++ ext/fts2/fts2.c 2009-09-14 18:17:02.000000000 -0700 |
-@@ -37,6 +37,20 @@ |
- ** This is an SQLite module implementing full-text search. |
- */ |
- |
-+/* TODO(shess): To make it easier to spot changes without groveling |
-+** through changelogs, I've defined GEARS_FTS2_CHANGES to call them |
-+** out, and I will document them here. On imports, these changes |
-+** should be reviewed to make sure they are still present, or are |
-+** dropped as appropriate. |
-+** |
-+** SQLite core adds the custom function fts2_tokenizer() to be used |
-+** for defining new tokenizers. The second parameter is a vtable |
-+** pointer encoded as a blob. Obviously this cannot be exposed to |
-+** Gears callers for security reasons. It could be suppressed in the |
-+** authorizer, but for now I have simply commented the definition out. |
-+*/ |
-+#define GEARS_FTS2_CHANGES 1 |
-+ |
- /* |
- ** The code in this file is only compiled if: |
- ** |
-@@ -335,6 +349,16 @@ |
- # define TRACE(A) |
- #endif |
- |
-+#if 0 |
-+/* Useful to set breakpoints. See main.c sqlite3Corrupt(). */ |
-+static int fts2Corrupt(void){ |
-+ return SQLITE_CORRUPT; |
-+} |
-+# define SQLITE_CORRUPT_BKPT fts2Corrupt() |
-+#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. |
-@@ -1814,7 +1838,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 " |
-@@ -3421,8 +3445,11 @@ |
- 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; |
- } |
- } |
- |
-@@ -3544,6 +3571,7 @@ |
- int firstIndex = pQuery->nTerms; |
- int iCol; |
- int nTerm = 1; |
-+ int iEndLast = -1; |
- |
- int rc = pModule->xOpen(pTokenizer, pSegment, nSegment, &pCursor); |
- if( rc!=SQLITE_OK ) return rc; |
-@@ -3568,6 +3596,20 @@ |
- pQuery->nextIsOr = 1; |
- continue; |
- } |
-+ |
-+ /* |
-+ * The ICU tokenizer considers '*' a break character, so the code below |
-+ * sets isPrefix correctly, but since that code doesn't eat the '*', the |
-+ * ICU tokenizer returns it as the next token. So eat it here until a |
-+ * better solution presents itself. |
-+ */ |
-+ if( pQuery->nTerms>0 && nToken==1 && pSegment[iBegin]=='*' && |
-+ iEndLast==iBegin){ |
-+ pQuery->pTerms[pQuery->nTerms-1].isPrefix = 1; |
-+ continue; |
-+ } |
-+ iEndLast = iEnd; |
-+ |
- queryAdd(pQuery, pToken, nToken); |
- if( !inPhrase && iBegin>0 && pSegment[iBegin-1]=='-' ){ |
- pQuery->pTerms[pQuery->nTerms-1].isNot = 1; |
-@@ -5077,6 +5119,9 @@ |
- ** the leaf data was entirely contained in the root), or from the |
- ** stream of blocks between iStartBlockid and iEndBlockid, inclusive. |
- */ |
-+/* TODO(shess): Figure out a means of indicating how many leaves are |
-+** expected, for purposes of detecting corruption. |
-+*/ |
- static int leavesReaderInit(fulltext_vtab *v, |
- int idx, |
- sqlite_int64 iStartBlockid, |
-@@ -5088,6 +5133,10 @@ |
- |
- dataBufferInit(&pReader->rootData, 0); |
- if( iStartBlockid==0 ){ |
-+ /* 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, |
-@@ -5098,22 +5147,48 @@ |
- 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 ) 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{ |
-+ leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
-+ } |
-+ } |
-+ |
-+ err: |
-+ if( rc!=SQLITE_OK ){ |
-+ if( idx==-1 ){ |
-+ sqlite3_finalize(s); |
-+ }else{ |
-+ sqlite3_reset(s); |
-+ } |
-+ return rc; |
- } |
-- if( rc!=SQLITE_ROW ) return rc; |
- |
- pReader->pStmt = s; |
-- leafReaderInit(sqlite3_column_blob(pReader->pStmt, 0), |
-- sqlite3_column_bytes(pReader->pStmt, 0), |
-- &pReader->leafReader); |
- } |
- return SQLITE_OK; |
- } |
-@@ -5136,10 +5211,22 @@ |
- 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{ |
-+ 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; |
-+ } |
-+ |
-+ leafReaderDestroy(&pReader->leafReader); |
-+ leafReaderInit(pLeafData, nLeafData, &pReader->leafReader); |
-+ } |
- } |
- return SQLITE_OK; |
- } |
-@@ -5200,8 +5287,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); |
-+ |
-+ /* 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; |
-+ } |
- |
-- assert( i<MERGE_COUNT ); |
- rc = leavesReaderInit(v, i, iStart, iEnd, pRootData, nRootData, |
- &pReaders[i]); |
- if( rc!=SQLITE_OK ) break; |
-@@ -5212,6 +5310,7 @@ |
- while( i-->0 ){ |
- leavesReaderDestroy(&pReaders[i]); |
- } |
-+ sqlite3_reset(s); /* So we don't leave a lock. */ |
- return rc; |
- } |
- |
-@@ -5295,10 +5394,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. |
- */ |
-@@ -5588,11 +5691,27 @@ |
- 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; |
-+ } |
-+ |
-+ getChildrenContaining(pData, nData, pTerm, nTerm, |
-+ isPrefix, piStartChild, piEndChild); |
-+ } |
- |
- /* We expect only one row. We must execute another sqlite3_step() |
- * to complete the iteration; otherwise the table will remain |
-@@ -5675,7 +5794,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 ); |
-@@ -5729,6 +5849,14 @@ |
- 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; |
-@@ -5748,6 +5876,7 @@ |
- } |
- |
- err: |
-+ sqlite3_reset(s); /* So we don't leave a lock. */ |
- dataBufferDestroy(&doclist); |
- return rc; |
- } |
-@@ -6240,6 +6369,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); |
-@@ -6253,6 +6390,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 ){ |
-@@ -6316,9 +6455,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) ){ |
-@@ -6822,7 +6970,11 @@ |
- ** module with sqlite. |
- */ |
- if( SQLITE_OK==rc |
-+#if GEARS_FTS2_CHANGES && !SQLITE_TEST |
-+ /* fts2_tokenizer() disabled for security reasons. */ |
-+#else |
- && SQLITE_OK==(rc = sqlite3Fts2InitHashTable(db, pHash, "fts2_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/fts2/fts2_icu.c |
-=================================================================== |
---- ext/fts2/fts2_icu.c 2009-09-03 13:32:06.000000000 -0700 |
-+++ ext/fts2/fts2_icu.c 2009-09-14 18:17:16.000000000 -0700 |
-@@ -198,7 +198,7 @@ |
- |
- while( iStart<iEnd ){ |
- int iWhite = iStart; |
-- U8_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); |
-+ U16_NEXT(pCsr->aChar, iWhite, pCsr->nChar, c); |
- if( u_isspace(c) ){ |
- iStart = iWhite; |
- }else{ |
-Index: ext/fts2/fts2_tokenizer.c |
-=================================================================== |
---- ext/fts2/fts2_tokenizer.c 2009-09-03 13:32:06.000000000 -0700 |
-+++ ext/fts2/fts2_tokenizer.c 2009-09-14 18:17:24.000000000 -0700 |
-@@ -33,6 +33,7 @@ |
- #include "fts2_hash.h" |
- #include "fts2_tokenizer.h" |
- #include <assert.h> |
-+#include <stddef.h> |
- |
- /* |
- ** Implementation of the SQL scalar function for accessing the underlying |
Index: ext/icu/icu.c |
=================================================================== |
--- ext/icu/icu.c 2009-09-03 13:32:06.000000000 -0700 |