diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 7a9ca71ea3..98e0a932b8 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -834,6 +834,9 @@ void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){ } } +/* +** Allocate a new SegReader object. +*/ int sqlite3Fts3SegReaderNew( Fts3Table *p, /* Virtual table handle */ int iAge, /* Segment "age". */ @@ -963,7 +966,8 @@ static int fts3SegReaderNew( } /* -** Compare the two Fts3SegReader structures. Comparison is as follows: +** Compare the entries pointed to by two Fts3SegReader structures. +** Comparison is as follows: ** ** 1) EOF is greater than not EOF. ** @@ -995,11 +999,22 @@ static int fts3SegReaderCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ return rc; } -static int fts3SegReaderCmp2(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ +/* +** A different comparison function for SegReader structures. In this +** version, it is assumed that each SegReader points to an entry in +** a doclist for identical terms. Comparison is made as follows: +** +** 1) EOF (end of doclist in this case) is greater than not EOF. +** +** 2) By current docid. +** +** 3) By segment age. An older segment is considered larger. +*/ +static int fts3SegReaderDoclistCmp(Fts3SegReader *pLhs, Fts3SegReader *pRhs){ int rc = (pLhs->pOffsetList==0)-(pRhs->pOffsetList==0); if( rc==0 ){ if( pLhs->iDocid==pRhs->iDocid ){ - rc = pRhs->iIdx-pLhs->iIdx; + rc = pRhs->iIdx - pLhs->iIdx; }else{ rc = (pLhs->iDocid > pRhs->iDocid) ? 1 : -1; } @@ -1075,9 +1090,10 @@ static void fts3SegReaderSort( ** Insert a record into the %_segments table. */ static int fts3WriteSegment( - Fts3Table *p, - sqlite3_int64 iBlock, - char *z, int n + Fts3Table *p, /* Virtual table handle */ + sqlite3_int64 iBlock, /* Block id for new block */ + char *z, /* Pointer to buffer containing block data */ + int n /* Size of buffer z in bytes */ ){ sqlite3_stmt *pStmt; int rc = fts3SqlStmt(p, SQL_INSERT_SEGMENTS, &pStmt, 0); @@ -1096,7 +1112,7 @@ static int fts3WriteSegment( ** Insert a record into the %_segdir table. */ static int fts3WriteSegdir( - Fts3Table *p, /* Virtual table handle */ + Fts3Table *p, /* Virtual table handle */ int iLevel, /* Value for "level" field */ int iIdx, /* Value for "idx" field */ sqlite3_int64 iStartBlock, /* Value for "start_block" field */ @@ -1122,16 +1138,23 @@ static int fts3WriteSegdir( return rc; } -static void fts3PrefixCompress( - const char *zPrev, - int nPrev, - const char *zNext, - int nNext, - int *pnPrefix +/* +** Return the size of the common prefix (if any) shared by zPrev and +** zNext, in bytes. For example, +** +** fts3PrefixCompress("abc", 3, "abcdef", 6) // returns 3 +** fts3PrefixCompress("abX", 3, "abcdef", 6) // returns 2 +** fts3PrefixCompress("abX", 3, "Xbcdef", 6) // returns 0 +*/ +static int fts3PrefixCompress( + const char *zPrev, /* Buffer containing previous term */ + int nPrev, /* Size of buffer zPrev in bytes */ + const char *zNext, /* Buffer containing next term */ + int nNext /* Size of buffer zNext in bytes */ ){ int n; for(n=0; nzTerm, pTree->nTerm, zTerm, nTerm, &nPrefix); + nPrefix = fts3PrefixCompress(pTree->zTerm, pTree->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; nReq += sqlite3Fts3VarintLen(nPrefix)+sqlite3Fts3VarintLen(nSuffix)+nSuffix; @@ -1263,10 +1286,20 @@ static int fts3TreeFinishNode( } /* -** Helper function for fts3NodeWrite(). +** Write the buffer for the segment node pTree and all of its peers to the +** database. Then call this function recursively to write the parent of +** pTree and its peers to the database. +** +** Except, if pTree is a root node, do not write it to the database. Instead, +** set output variables *paRoot and *pnRoot to contain the root node. +** +** If successful, SQLITE_OK is returned and output variable *piLast is +** set to the largest blockid written to the database (or zero if no +** blocks were written to the db). Otherwise, an SQLite error code is +** returned. */ static int fts3NodeWrite( - Fts3Table *p, /* Virtual table handle */ + Fts3Table *p, /* Virtual table handle */ SegmentNode *pTree, /* SegmentNode handle */ int iHeight, /* Height of this node in tree */ sqlite3_int64 iLeaf, /* Block id of first leaf node */ @@ -1326,6 +1359,14 @@ static void fts3NodeFree(SegmentNode *pTree){ } } +/* +** Add a term to the segment being constructed by the SegmentWriter object +** *ppWriter. When adding the first term to a segment, *ppWriter should +** be passed NULL. This function will allocate a new SegmentWriter object +** and return it via the input/output variable *ppWriter in this case. +** +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +*/ static int fts3SegWriterAdd( Fts3Table *p, /* Virtual table handle */ SegmentWriter **ppWriter, /* IN/OUT: SegmentWriter handle */ @@ -1368,7 +1409,7 @@ static int fts3SegWriterAdd( } nData = pWriter->nData; - fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm, &nPrefix); + nPrefix = fts3PrefixCompress(pWriter->zTerm, pWriter->nTerm, zTerm, nTerm); nSuffix = nTerm-nPrefix; /* Figure out how many bytes are required by this new entry */ @@ -1458,18 +1499,26 @@ static int fts3SegWriterAdd( return SQLITE_OK; } +/* +** Flush all data associated with the SegmentWriter object pWriter to the +** database. This function must be called after all terms have been added +** to the segment using fts3SegWriterAdd(). If successful, SQLITE_OK is +** returned. Otherwise, an SQLite error code. +*/ static int fts3SegWriterFlush( - Fts3Table *p, - SegmentWriter *pWriter, - int iLevel, - int iIdx + Fts3Table *p, /* Virtual table handle */ + SegmentWriter *pWriter, /* SegmentWriter to flush to the db */ + int iLevel, /* Value for 'level' column of %_segdir */ + int iIdx /* Value for 'idx' column of %_segdir */ ){ - int rc; + int rc; /* Return code */ if( pWriter->pTree ){ - sqlite3_int64 iLast; - char *zRoot; - int nRoot; - sqlite3_int64 iLastLeaf = pWriter->iFree; + sqlite3_int64 iLast; /* Largest block id written to database */ + sqlite3_int64 iLastLeaf; /* Largest leaf block id written to db */ + char *zRoot; /* Pointer to buffer containing root node */ + int nRoot; /* Size of buffer zRoot */ + + iLastLeaf = pWriter->iFree; rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, pWriter->nData); if( rc==SQLITE_OK ){ rc = fts3NodeWrite(p, pWriter->pTree, 1, @@ -1487,6 +1536,10 @@ static int fts3SegWriterFlush( return rc; } +/* +** Release all memory held by the SegmentWriter object passed as the +** first argument. +*/ static void fts3SegWriterFree(SegmentWriter *pWriter){ if( pWriter ){ sqlite3_free(pWriter->aData); @@ -1519,6 +1572,11 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){ return rc; } +/* +** Set *pnSegment to the number of segments of level iLevel in the database. +** +** Return SQLITE_OK if successful, or an SQLite error code if not. +*/ static int fts3SegmentCount(Fts3Table *p, int iLevel, int *pnSegment){ sqlite3_stmt *pStmt; int rc; @@ -1533,6 +1591,13 @@ static int fts3SegmentCount(Fts3Table *p, int iLevel, int *pnSegment){ return sqlite3_reset(pStmt); } +/* +** Set *pnSegment to the total number of segments in the database. Set +** *pnMax to the largest segment level in the database (segment levels +** are stored in the 'level' column of the %_segdir table). +** +** Return SQLITE_OK if successful, or an SQLite error code if not. +*/ static int fts3SegmentCountMax(Fts3Table *p, int *pnSegment, int *pnMax){ sqlite3_stmt *pStmt; int rc; @@ -1546,11 +1611,25 @@ static int fts3SegmentCountMax(Fts3Table *p, int *pnSegment, int *pnMax){ return sqlite3_reset(pStmt); } +/* +** This function is used after merging multiple segments into a single large +** segment to delete the old, now redundant, segment b-trees. Specifically, +** it: +** +** 1) Deletes all %_segments entries for the segments associated with +** each of the SegReader objects in the array passed as the third +** argument, and +** +** 2) deletes all %_segdir entries with level iLevel, or all %_segdir +** entries regardless of level if (iLevel<0). +** +** SQLITE_OK is returned if successful, otherwise an SQLite error code. +*/ static int fts3DeleteSegdir( - Fts3Table *p, - int iLevel, - Fts3SegReader **apSegment, - int nReader + Fts3Table *p, /* Virtual table handle */ + int iLevel, /* Level of %_segdir entries to delete */ + Fts3SegReader **apSegment, /* Array of SegReader objects */ + int nReader /* Size of array apSegment */ ){ int rc; /* Return Code */ int i; /* Iterator variable */ @@ -1584,7 +1663,20 @@ static int fts3DeleteSegdir( return rc; } -static void fts3ColumnFilter(int iCol, char **ppList, int *pnList){ +/* +** When this function is called, buffer *ppList (size *pnList bytes) contains +** a position list that may (or may not) feature multiple columns. This +** function adjusts the pointer *ppList and the length *pnList so that they +** identify the subset of the position list that corresponds to column iCol. +** +** If there are no entries in the input position list for column iCol, then +** *pnList is set to zero before returning. +*/ +static void fts3ColumnFilter( + int iCol, /* Column to filter on */ + char **ppList, /* IN/OUT: Pointer to position list */ + int *pnList /* IN/OUT: Size of buffer *ppList in bytes */ +){ char *pList = *ppList; int nList = *pnList; char *pEnd = &pList[nList]; @@ -1614,6 +1706,10 @@ static void fts3ColumnFilter(int iCol, char **ppList, int *pnList){ *pnList = nList; } +/* +** sqlite3Fts3SegReaderIterate() callback used when merging multiple +** segments to create a single, larger segment. +*/ static int fts3MergeCallback( Fts3Table *p, void *pContext, @@ -1707,7 +1803,7 @@ int sqlite3Fts3SegReaderIterate( for(i=0; ipOffsetList ){ int j; /* Number of segments that share a docid */ char *pList; @@ -1749,7 +1845,7 @@ int sqlite3Fts3SegReaderIterate( } } - fts3SegReaderSort(apSegment, nMerge, j, fts3SegReaderCmp2); + fts3SegReaderSort(apSegment, nMerge, j, fts3SegReaderDoclistCmp); } if( nDoclist>0 ){ diff --git a/manifest b/manifest index 9f90bf1e97..c6aa4ae3cf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sa\stest\sto\smake\ssure\sa\sdatabase\scan\sbe\sattached\sto\sa\ssingle\shandle\stwice\sif\snot\sin\sshared-cache\smode. -D 2009-11-20T10:18:06 +C Merge\sleaf\saccidentally\screated\sby\s[1c4984c62f]. +D 2009-11-20T10:23:13 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 7f6c6aa7feeeb5e26e01b344161d9aa1b5d64177 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -68,7 +68,7 @@ F ext/fts3/fts3_snippet.c 082f2906deaaa2656f19b88834e89d099352af6e F ext/fts3/fts3_tokenizer.c 36f78d1a43a29b0feaec1ced6da9e56b9c653d1f F ext/fts3/fts3_tokenizer.h 7ff73caa3327589bf6550f60d93ebdd1f6a0fb5c F ext/fts3/fts3_tokenizer1.c 0a5bcc579f35de5d24a9345d7908dc25ae403ee7 -F ext/fts3/fts3_write.c 6b9b4fd998fc2cbc05859b79af559b32792023ab +F ext/fts3/fts3_write.c 69e6fb5a387aa7eb1f9d89e5bce35d21b879602e F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2 @@ -162,7 +162,7 @@ F src/printf.c 03fabdd6112a0e23f78f8ac9a1396947ade0273b F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c aa3cb21e1ecd905c071fce8fb64d1a166cefc239 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 -F src/select.c a727f61f3267bfa20ce1c3e85d38dc2132db1060 +F src/select.c 2f9ed7482e7a25b0b127fc41693bbdbe1caf5647 F src/shell.c f4948cb6d30665d755a6b5e0ec313d1094aab828 F src/sqlite.h.in 4464e9772122f0447305d425e04d122b6f1bffec F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 @@ -209,7 +209,7 @@ F src/update.c 8efeb09822886e33c265dd96d29a3d865ea6dcf2 F src/utf.c dad16adcc0c35ef2437dca125a4b07419d361052 F src/util.c ad4f03079ba0fe83590d1cc9197e8e4844e38592 F src/vacuum.c 03309a08d549f9389cc3a3589afd4fadbdaf0679 -F src/vdbe.c 95fa2b51a4e602f74594bd9a0f679b7eaf44f9c0 +F src/vdbe.c 89d618dd0b4544e319dfab84db7356e7ee5aa430 F src/vdbe.h 5f35750615163d1064052785b4a9f0eb004a720d F src/vdbeInt.h d7ea821ac7813c9bea0fe87558c35e07b2c7c44d F src/vdbeapi.c 17680ab7a75ec938c5ba039a6c87489d01faf2cb @@ -772,7 +772,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 9a429349ccc2fa9acd28365a86578f602e87dafb -R 46119cb7f99f2b8740a6d715a49a25dc +P 1c4984c62f393f41f9182ea82546c16d02efa46f c6ed7e2a73a7a65cfa914ffcad4f603b6b7a22a8 +R a4c740bd2d6cd6d5d405c025a9a5ce19 U dan -Z 45d94d950c686cbe6192e3168ebbb70a +Z 4d4aca1de07a44952499e25e5fd5b2ca diff --git a/manifest.uuid b/manifest.uuid index 96361d7671..24c2c498f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1c4984c62f393f41f9182ea82546c16d02efa46f \ No newline at end of file +cae949ce971ca216e0f8880b2f93866619fa05be \ No newline at end of file diff --git a/src/select.c b/src/select.c index d6b7c0bdb9..7555a391c2 100644 --- a/src/select.c +++ b/src/select.c @@ -1323,11 +1323,10 @@ static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ v = sqlite3GetVdbe(pParse); if( NEVER(v==0) ) return; /* VDBE should have already been allocated */ if( sqlite3ExprIsInteger(p->pLimit, &n) ){ + sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); + VdbeComment((v, "LIMIT counter")); if( n==0 ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, iBreak); - }else{ - sqlite3VdbeAddOp2(v, OP_Integer, n, iLimit); - VdbeComment((v, "LIMIT counter")); } }else{ sqlite3ExprCode(pParse, p->pLimit, iLimit); diff --git a/src/vdbe.c b/src/vdbe.c index 90dd90e67b..17afa4e583 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -543,6 +543,7 @@ int sqlite3VdbeExec( Op *pOp; /* Current operation */ int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ + u8 resetSchemaOnFault = 0; /* Reset schema after an error if true */ u8 encoding = ENC(db); /* The database encoding */ #ifndef SQLITE_OMIT_PROGRESS_CALLBACK u8 checkProgress; /* True if progress callbacks are enabled */ @@ -4430,6 +4431,7 @@ case OP_Destroy: { /* out2-prerelease */ #ifndef SQLITE_OMIT_AUTOVACUUM if( rc==SQLITE_OK && iMoved!=0 ){ sqlite3RootPageMoved(&db->aDb[iDb], iMoved, pOp->p1); + resetSchemaOnFault = 1; } #endif } @@ -5709,6 +5711,7 @@ vdbe_error_halt: sqlite3VdbeHalt(p); if( rc==SQLITE_IOERR_NOMEM ) db->mallocFailed = 1; rc = SQLITE_ERROR; + if( resetSchemaOnFault ) sqlite3ResetInternalSchema(db, 0); /* This is the only way out of this procedure. We have to ** release the mutexes on btrees that were acquired at the