From: dan Date: Fri, 20 Nov 2009 05:05:19 +0000 (+0000) Subject: Improve comments and other things in fts3_write.c. X-Git-Tag: version-3.7.2~808 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d1414c58e5d7998bf154df9b5a16f0c36e298c98;p=thirdparty%2Fsqlite.git Improve comments and other things in fts3_write.c. FossilOrigin-Name: 1cf0e3cc14bad22867e740736c2886dc1c4a48dc --- diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index ec3d00e5d1..7a9ca71ea3 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -147,11 +147,22 @@ struct SegmentNode { #define SQL_CONTENT_INSERT 16 #define SQL_GET_BLOCK 17 +/* +** This function is used to obtain an SQLite prepared statement handle +** for the statement identified by the second argument. If successful, +** *pp is set to the requested statement handle and SQLITE_OK returned. +** Otherwise, an SQLite error code is returned and *pp is set to 0. +** +** If argument apVal is not NULL, then it must point to an array with +** at least as many entries as the requested statement has bound +** parameters. The values are bound to the statements parameters before +** returning. +*/ static int fts3SqlStmt( - Fts3Table *p, - int eStmt, - sqlite3_stmt **pp, - sqlite3_value **apVal + Fts3Table *p, /* Virtual table handle */ + int eStmt, /* One of the SQL_XXX constants above */ + sqlite3_stmt **pp, /* OUT: Statement handle */ + sqlite3_value **apVal /* Values to bind to statement */ ){ const char *azSql[] = { /* 0 */ "DELETE FROM %Q.'%q_content' WHERE rowid = ?", @@ -176,9 +187,8 @@ static int fts3SqlStmt( /* 14 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", /* 15 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", -/* 16 */ 0, /* CONTENT_INSERT - generated elsewhere */ +/* 16 */ "INSERT INTO %Q.'%q_content' VALUES(%z)", /* 17 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?", - }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; @@ -188,7 +198,25 @@ static int fts3SqlStmt( pStmt = p->aStmt[eStmt]; if( !pStmt ){ - char *zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); + char *zSql; + if( eStmt==SQL_CONTENT_INSERT ){ + int i; /* Iterator variable */ + char *zVarlist; /* The "?, ?, ..." string */ + zVarlist = (char *)sqlite3_malloc(2*p->nColumn+2); + if( !zVarlist ){ + *pp = 0; + return SQLITE_NOMEM; + } + zVarlist[0] = '?'; + zVarlist[p->nColumn*2+1] = '\0'; + for(i=1; i<=p->nColumn; i++){ + zVarlist[i*2-1] = ','; + zVarlist[i*2] = '?'; + } + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, zVarlist); + }else{ + zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName); + } if( !zSql ){ rc = SQLITE_NOMEM; }else{ @@ -209,6 +237,25 @@ static int fts3SqlStmt( return rc; } +/* +** Similar to fts3SqlStmt(). Except, after binding the parameters in +** array apVal[] to the SQL statement identified by eStmt, the statement +** is executed. +** +** Returns SQLITE_OK if the statement is successfully executed, or an +** SQLite error code otherwise. +*/ +static int fts3SqlExec(Fts3Table *p, int eStmt, sqlite3_value **apVal){ + sqlite3_stmt *pStmt; + int rc = fts3SqlStmt(p, eStmt, &pStmt, apVal); + if( rc==SQLITE_OK ){ + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + return rc; +} + + /* ** Read a single block from the %_segments table. If the specified block ** does not exist, return SQLITE_CORRUPT. If some other error (malloc, IO @@ -268,16 +315,18 @@ int sqlite3Fts3AllSegdirs(Fts3Table *p, sqlite3_stmt **ppStmt){ } -static int fts3SqlExec(Fts3Table *p, int eStmt, sqlite3_value **apVal){ - sqlite3_stmt *pStmt; - int rc = fts3SqlStmt(p, eStmt, &pStmt, apVal); - if( rc==SQLITE_OK ){ - sqlite3_step(pStmt); - rc = sqlite3_reset(pStmt); - } - return rc; -} - +/* +** Append a single varint to a PendingList buffer. SQLITE_OK is returned +** if successful, or an SQLite error code otherwise. +** +** This function also serves to allocate the PendingList structure itself. +** For example, to create a new PendingList structure containing two +** varints: +** +** PendingList *p = 0; +** fts3PendingListAppendVarint(&p, 1); +** fts3PendingListAppendVarint(&p, 2); +*/ static int fts3PendingListAppendVarint( PendingList **pp, /* IN/OUT: Pointer to PendingList struct */ sqlite3_int64 i /* Value to append to data */ @@ -313,12 +362,21 @@ static int fts3PendingListAppendVarint( return SQLITE_OK; } +/* +** Add a docid/column/position entry to a PendingList structure. Non-zero +** is returned if the structure is sqlite3_realloced as part of adding +** the entry. Otherwise, zero. +** +** If an OOM error occurs, *pRc is set to SQLITE_NOMEM before returning. +** Zero is always returned in this case. Otherwise, if no OOM error occurs, +** it is set to SQLITE_OK. +*/ static int fts3PendingListAppend( - PendingList **pp, - sqlite3_int64 iDocid, - sqlite3_int64 iCol, - sqlite3_int64 iPos, - int *pRc + PendingList **pp, /* IN/OUT: PendingList structure */ + sqlite3_int64 iDocid, /* Docid for entry to add */ + sqlite3_int64 iCol, /* Column for entry to add */ + sqlite3_int64 iPos, /* Position of term for entry to add */ + int *pRc /* OUT: Return code */ ){ PendingList *p = *pp; int rc = SQLITE_OK; @@ -363,6 +421,13 @@ static int fts3PendingListAppend( return 0; } +/* +** Tokenize the nul-terminated string zText and add all tokens to the +** pending-terms hash-table. The docid used is that currently stored in +** p->iPrevDocid, and the column is specified by argument iCol. +** +** If successful, SQLITE_OK is returned. Otherwise, an SQLite error code. +*/ static int fts3PendingTermsAdd(Fts3Table *p, const char *zText, int iCol){ int rc; int iStart; @@ -497,47 +562,19 @@ static int fts3InsertData( sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ /* Locate the statement handle used to insert data into the %_content - ** table. If no such statement has been prepared, prepare a new one. - ** The SQL for this statement is: + ** table. The SQL for this statement is: ** ** INSERT INTO %_content VALUES(?, ?, ?, ...) ** ** The statement features N '?' variables, where N is the number of user ** defined columns in the FTS3 table, plus one for the docid field. */ - pContentInsert = p->aStmt[SQL_CONTENT_INSERT]; - if( !pContentInsert ){ - char *zVarlist; /* The "?, ?, ..." string */ - char *zSql; /* The text of the INSERT statement */ - - /* Construct the SQL statement text. */ - zVarlist = (char *)sqlite3_malloc(2*p->nColumn+2); - if( !zVarlist ){ - return SQLITE_NOMEM; - } - zVarlist[0] = '?'; - for(i=1; i<=p->nColumn; i++){ - zVarlist[i*2-1] = ','; - zVarlist[i*2] = '?'; - } - zVarlist[p->nColumn*2+1] = '\0'; - zSql = sqlite3_mprintf("INSERT INTO %Q.'%q_content' VALUES(%z)", - p->zDb, p->zName, zVarlist - ); - if( !zSql ) return SQLITE_NOMEM; - - /* Prepare the SQL statement. */ - rc = sqlite3_prepare_v2(p->db, zSql, -1, &pContentInsert, NULL); - sqlite3_free(zSql); - if( rc!=SQLITE_OK ){ - return rc; - } - p->aStmt[SQL_CONTENT_INSERT] = pContentInsert; + rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); + if( rc!=SQLITE_OK ){ + return rc; } - /* Bind values to the prepared statement. - ** - ** There is a quirk here. The users INSERT statement may have specified + /* There is a quirk here. The users INSERT statement may have specified ** a value for the "rowid" field, for the "docid" field, or for both. ** Which is a problem, since "rowid" and "docid" are aliases for the ** same value. For example: @@ -547,10 +584,6 @@ static int fts3InsertData( ** In FTS3, if a non-NULL docid value is specified, it is the value ** inserted. Otherwise, the rowid value is used. */ - for(i=0; i<=p->nColumn; i++){ - rc = sqlite3_bind_value(pContentInsert, i+1, apVal[i+1]); - if( rc!=SQLITE_OK ) return rc; - } if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ rc = sqlite3_bind_value(pContentInsert, 1, apVal[3+p->nColumn]); if( rc!=SQLITE_OK ) return rc; @@ -616,6 +649,10 @@ static int fts3DeleteTerms(Fts3Table *p, sqlite3_value **apVal){ return sqlite3_reset(pSelect); } +/* +** Forward declaration to account for the circular dependency between +** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). +*/ static int fts3SegmentMerge(Fts3Table *, int); /* @@ -719,6 +756,10 @@ static int fts3SegReaderNext(Fts3SegReader *pReader){ return SQLITE_OK; } +/* +** Set the SegReader to point to the first docid in the doclist associated +** with the current term. +*/ static void fts3SegReaderFirstDocid(Fts3SegReader *pReader){ int n; assert( pReader->aDoclist ); @@ -728,15 +769,14 @@ static void fts3SegReaderFirstDocid(Fts3SegReader *pReader){ } /* -** +** Advance the SegReader to point to the next docid in the doclist +** associated with the current term. +** ** If arguments ppOffsetList and pnOffsetList are not NULL, then ** *ppOffsetList is set to point to the first column-offset list ** in the doclist entry (i.e. immediately past the docid varint). ** *pnOffsetList is set to the length of the set of column-offset ** lists, not including the nul-terminator byte. For example: -** -** TODO: example. -** */ static void fts3SegReaderNextDocid( Fts3SegReader *pReader, @@ -776,12 +816,15 @@ static void fts3SegReaderNextDocid( } /* -** Free all allocations associated with the iterator passed as the first -** argument. +** Free all allocations associated with the iterator passed as the +** second argument. */ void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){ if( pReader ){ if( pReader->pStmt ){ + /* Move the leaf-range SELECT statement to the aLeavesStmt[] array, + ** so that it can be reused when required by another query. + */ assert( p->nLeavesStmtnLeavesTotal ); sqlite3_reset(pReader->pStmt); p->aLeavesStmt[p->nLeavesStmt++] = pReader->pStmt; @@ -825,6 +868,11 @@ int sqlite3Fts3SegReaderNew( memcpy(pReader->aNode, zRoot, nRoot); }else{ sqlite3_stmt *pStmt; + + /* If the text of the SQL statement to iterate through a contiguous + ** set of entries in the %_segments table has not yet been composed, + ** compose it now. + */ if( !p->zSelectLeaves ){ p->zSelectLeaves = sqlite3_mprintf( "SELECT block FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ? " @@ -835,6 +883,11 @@ int sqlite3Fts3SegReaderNew( goto finished; } } + + /* If there are no free statements in the aLeavesStmt[] array, prepare + ** a new statement now. Otherwise, reuse a prepared statement from + ** aLeavesStmt[]. + */ if( p->nLeavesStmt==0 ){ if( p->nLeavesTotal==p->nLeavesAlloc ){ int nNew = p->nLeavesAlloc + 16; @@ -856,6 +909,8 @@ int sqlite3Fts3SegReaderNew( }else{ pReader->pStmt = p->aLeavesStmt[--p->nLeavesStmt]; } + + /* Bind the start and end leaf blockids to the prepared SQL statement. */ sqlite3_bind_int64(pReader->pStmt, 1, iStartLeaf); sqlite3_bind_int64(pReader->pStmt, 2, iEndLeaf); } @@ -1645,7 +1700,7 @@ int sqlite3Fts3SegReaderIterate( int nDoclist = 0; /* Size of doclist */ sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ - /* The current term of the first nMerge entries in the linked list + /* The current term of the first nMerge entries in the array ** of Fts3SegReader objects is the same. The doclists must be merged ** and a single term added to the new segment. */ diff --git a/manifest b/manifest index 85c48d7902..28a1090383 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\soptimizations\sto\sfts3\scode. -D 2009-11-20T02:24:15 +C Improve\scomments\sand\sother\sthings\sin\sfts3_write.c. +D 2009-11-20T05:05:19 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 3c8a5d912af939232480b3f4064ac49621816250 +F ext/fts3/fts3_write.c 6b9b4fd998fc2cbc05859b79af559b32792023ab F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/icu/README.txt 3b130aa66e7a681136f6add198b076a2f90d1e33 F ext/icu/icu.c 12e763d288d23b5a49de37caa30737b971a2f1e2 @@ -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 4115c0c286052e32cb81f77a644d530c1766206f -R d93aed1e18b2651263389c52f5a6aa80 +P b456eacbbb16513d1b27e90015ea58a6dc92cc3b +R 70a25367badaa9e85b170e396db9833f U dan -Z 234100290840447274601364a421931c +Z 5ffc5a8c993fa4958f562d1dcf7d0c6b diff --git a/manifest.uuid b/manifest.uuid index 92feca51d4..c222c6dfc8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b456eacbbb16513d1b27e90015ea58a6dc92cc3b \ No newline at end of file +1cf0e3cc14bad22867e740736c2886dc1c4a48dc \ No newline at end of file