Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Improve comments and other things in fts3_write.c. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
1cf0e3cc14bad22867e740736c2886dc |
User & Date: | dan 2009-11-20 05:05:19.000 |
Context
2009-11-20
| ||
13:18 | Avoid unnecessary page cache allocations when move a page while autovacuuming an in-memory database, since the allocation might fail making it impossible to rollback the transaction. (check-in: 9a429349cc user: drh tags: trunk) | |
05:05 | Improve comments and other things in fts3_write.c. (check-in: 1cf0e3cc14 user: dan tags: trunk) | |
02:24 | Minor optimizations to fts3 code. (check-in: b456eacbbb user: dan tags: trunk) | |
Changes
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
143 144 145 146 147 148 149 150 | #define SQL_SELECT_LEVEL_COUNT 12 #define SQL_SELECT_SEGDIR_COUNT_MAX 13 #define SQL_DELETE_SEGDIR_BY_LEVEL 14 #define SQL_DELETE_SEGMENTS_RANGE 15 #define SQL_CONTENT_INSERT 16 #define SQL_GET_BLOCK 17 static int fts3SqlStmt( | > > > > > > > > > > > | | | | | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | #define SQL_SELECT_LEVEL_COUNT 12 #define SQL_SELECT_SEGDIR_COUNT_MAX 13 #define SQL_DELETE_SEGDIR_BY_LEVEL 14 #define SQL_DELETE_SEGMENTS_RANGE 15 #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, /* 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 = ?", /* 1 */ "SELECT NOT EXISTS(SELECT docid FROM %Q.'%q_content' WHERE rowid!=?)", /* 2 */ "DELETE FROM %Q.'%q_content'", /* 3 */ "DELETE FROM %Q.'%q_segments'", /* 4 */ "DELETE FROM %Q.'%q_segdir'", |
︙ | ︙ | |||
172 173 174 175 176 177 178 | "FROM %Q.'%q_segdir' ORDER BY level DESC, idx ASC", /* 12 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", /* 13 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'", /* 14 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", /* 15 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", | | < > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | "FROM %Q.'%q_segdir' ORDER BY level DESC, idx ASC", /* 12 */ "SELECT count(*) FROM %Q.'%q_segdir' WHERE level = ?", /* 13 */ "SELECT count(*), max(level) FROM %Q.'%q_segdir'", /* 14 */ "DELETE FROM %Q.'%q_segdir' WHERE level = ?", /* 15 */ "DELETE FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ?", /* 16 */ "INSERT INTO %Q.'%q_content' VALUES(%z)", /* 17 */ "SELECT block FROM %Q.'%q_segments' WHERE blockid = ?", }; int rc = SQLITE_OK; sqlite3_stmt *pStmt; assert( SizeofArray(azSql)==SizeofArray(p->aStmt) ); assert( eStmt<SizeofArray(azSql) && eStmt>=0 ); pStmt = p->aStmt[eStmt]; if( !pStmt ){ 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{ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, NULL); sqlite3_free(zSql); assert( rc==SQLITE_OK || pStmt==0 ); p->aStmt[eStmt] = pStmt; } } if( apVal ){ int i; int nParam = sqlite3_bind_parameter_count(pStmt); for(i=0; rc==SQLITE_OK && i<nParam; i++){ rc = sqlite3_bind_value(pStmt, i+1, apVal[i]); } } *pp = pStmt; 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 ** etc.) occurs, return the appropriate SQLite error code. ** ** Otherwise, if successful, set *pzBlock to point to a buffer containing |
︙ | ︙ | |||
264 265 266 267 268 269 270 | ** 4: root */ int sqlite3Fts3AllSegdirs(Fts3Table *p, sqlite3_stmt **ppStmt){ return fts3SqlStmt(p, SQL_SELECT_ALL_LEVEL, ppStmt, 0); } | < < < > | > > | | < | < | > > > > | 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | ** 4: root */ int sqlite3Fts3AllSegdirs(Fts3Table *p, sqlite3_stmt **ppStmt){ return fts3SqlStmt(p, SQL_SELECT_ALL_LEVEL, ppStmt, 0); } /* ** 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 */ ){ PendingList *p = *pp; /* Allocate or grow the PendingList as required. */ |
︙ | ︙ | |||
309 310 311 312 313 314 315 316 | /* Append the new serialized varint to the end of the list. */ p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); p->aData[p->nData] = '\0'; *pp = p; return SQLITE_OK; } static int fts3PendingListAppend( | > > > > > > > > > | | | | | | 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | /* Append the new serialized varint to the end of the list. */ p->nData += sqlite3Fts3PutVarint(&p->aData[p->nData], i); p->aData[p->nData] = '\0'; *pp = p; 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, /* 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; assert( !p || p->iLastDocid<=iDocid ); if( !p || p->iLastDocid!=iDocid ){ |
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 369 370 371 372 | if( p!=*pp ){ *pp = p; return 1; } return 0; } static int fts3PendingTermsAdd(Fts3Table *p, const char *zText, int iCol){ int rc; int iStart; int iEnd; int iPos; char const *zToken; | > > > > > > > | 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | if( p!=*pp ){ *pp = p; return 1; } 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; int iEnd; int iPos; char const *zToken; |
︙ | ︙ | |||
493 494 495 496 497 498 499 | sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ ){ int rc; /* Return code */ int i; /* Iterator variable */ sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ /* Locate the statement handle used to insert data into the %_content | < | < < < < | < < < < < < < < < < < < < < < < < < < | | | < | < < < | < < < < | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 | sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ ){ int rc; /* Return code */ int i; /* Iterator variable */ sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ /* Locate the statement handle used to insert data into the %_content ** 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. */ rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); if( rc!=SQLITE_OK ){ return rc; } /* 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: ** ** INSERT INTO fts3tbl(rowid, docid) VALUES(1, 2); ** ** In FTS3, if a non-NULL docid value is specified, it is the value ** inserted. Otherwise, the rowid value is used. */ 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; } /* Execute the statement to insert the record. Set *piDocid to the ** new docid value. |
︙ | ︙ | |||
612 613 614 615 616 617 618 619 620 621 622 623 624 625 | } } } return sqlite3_reset(pSelect); } static int fts3SegmentMerge(Fts3Table *, int); /* ** This function allocates a new level iLevel index in the segdir table. ** Usually, indexes are allocated within a level sequentially starting ** with 0, so the allocated index is one greater than the value returned ** by: | > > > > | 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | } } } return sqlite3_reset(pSelect); } /* ** Forward declaration to account for the circular dependency between ** functions fts3SegmentMerge() and fts3AllocateSegdirIdx(). */ static int fts3SegmentMerge(Fts3Table *, int); /* ** This function allocates a new level iLevel index in the segdir table. ** Usually, indexes are allocated within a level sequentially starting ** with 0, so the allocated index is one greater than the value returned ** by: |
︙ | ︙ | |||
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist); assert( pNext<&pReader->aNode[pReader->nNode] ); pReader->aDoclist = pNext; pReader->pOffsetList = 0; return SQLITE_OK; } static void fts3SegReaderFirstDocid(Fts3SegReader *pReader){ int n; assert( pReader->aDoclist ); assert( !pReader->pOffsetList ); n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); pReader->pOffsetList = &pReader->aDoclist[n]; } /* | > > > > > > | < < < | 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 | pNext += sqlite3Fts3GetVarint32(pNext, &pReader->nDoclist); assert( pNext<&pReader->aNode[pReader->nNode] ); pReader->aDoclist = pNext; pReader->pOffsetList = 0; 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 ); assert( !pReader->pOffsetList ); n = sqlite3Fts3GetVarint(pReader->aDoclist, &pReader->iDocid); pReader->pOffsetList = &pReader->aDoclist[n]; } /* ** 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: */ static void fts3SegReaderNextDocid( Fts3SegReader *pReader, char **ppOffsetList, int *pnOffsetList ){ char *p = pReader->pOffsetList; |
︙ | ︙ | |||
772 773 774 775 776 777 778 | sqlite3_int64 iDelta; pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta); pReader->iDocid += iDelta; } } /* | | | > > > | 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | sqlite3_int64 iDelta; pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta); pReader->iDocid += iDelta; } } /* ** 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->nLeavesStmt<p->nLeavesTotal ); sqlite3_reset(pReader->pStmt); p->aLeavesStmt[p->nLeavesStmt++] = pReader->pStmt; } sqlite3_free(pReader->zTerm); sqlite3_free(pReader); } |
︙ | ︙ | |||
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | if( nExtra ){ /* The entire segment is stored in the root node. */ pReader->aNode = (char *)&pReader[1]; pReader->nNode = nRoot; memcpy(pReader->aNode, zRoot, nRoot); }else{ sqlite3_stmt *pStmt; if( !p->zSelectLeaves ){ p->zSelectLeaves = sqlite3_mprintf( "SELECT block FROM %Q.'%q_segments' WHERE blockid BETWEEN ? AND ? " "ORDER BY blockid", p->zDb, p->zName ); if( !p->zSelectLeaves ){ rc = SQLITE_NOMEM; goto finished; } } if( p->nLeavesStmt==0 ){ if( p->nLeavesTotal==p->nLeavesAlloc ){ int nNew = p->nLeavesAlloc + 16; sqlite3_stmt **aNew = (sqlite3_stmt **)sqlite3_realloc( p->aLeavesStmt, nNew*sizeof(sqlite3_stmt *) ); if( !aNew ){ | > > > > > > > > > > | 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 | if( nExtra ){ /* The entire segment is stored in the root node. */ pReader->aNode = (char *)&pReader[1]; pReader->nNode = nRoot; 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 ? " "ORDER BY blockid", p->zDb, p->zName ); if( !p->zSelectLeaves ){ rc = SQLITE_NOMEM; 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; sqlite3_stmt **aNew = (sqlite3_stmt **)sqlite3_realloc( p->aLeavesStmt, nNew*sizeof(sqlite3_stmt *) ); if( !aNew ){ |
︙ | ︙ | |||
852 853 854 855 856 857 858 859 860 861 862 863 864 865 | if( rc!=SQLITE_OK ){ goto finished; } p->nLeavesTotal++; }else{ pReader->pStmt = p->aLeavesStmt[--p->nLeavesStmt]; } sqlite3_bind_int64(pReader->pStmt, 1, iStartLeaf); sqlite3_bind_int64(pReader->pStmt, 2, iEndLeaf); } rc = fts3SegReaderNext(pReader); finished: if( rc==SQLITE_OK ){ | > > | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 | if( rc!=SQLITE_OK ){ goto finished; } p->nLeavesTotal++; }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); } rc = fts3SegReaderNext(pReader); finished: if( rc==SQLITE_OK ){ |
︙ | ︙ | |||
1641 1642 1643 1644 1645 1646 1647 | Fts3SegReader *p0 = apSegment[0]; rc = xFunc(p, pContext, zTerm, nTerm, p0->aDoclist, p0->nDoclist); if( rc!=SQLITE_OK ) goto finished; }else{ int nDoclist = 0; /* Size of doclist */ sqlite3_int64 iPrev = 0; /* Previous docid stored in doclist */ | | | 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 | Fts3SegReader *p0 = apSegment[0]; rc = xFunc(p, pContext, zTerm, nTerm, p0->aDoclist, p0->nDoclist); if( rc!=SQLITE_OK ) goto finished; }else{ 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 array ** of Fts3SegReader objects is the same. The doclists must be merged ** and a single term added to the new segment. */ for(i=0; i<nMerge; i++){ fts3SegReaderFirstDocid(apSegment[i]); } fts3SegReaderSort(apSegment, nMerge, nMerge, fts3SegReaderCmp2); |
︙ | ︙ |